--- /dev/null
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+\f
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+\f
+ Appendix: How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
-This is a subset of Shapelib v1.3.0 from http://shapelib.maptools.org/
+This is a subset of Shapelib v1.4.1 from http://shapelib.maptools.org/
-The source is largely unmodified. It's subsetted here only to reduce
+The source is unmodified. It's subsetted here only to reduce
the amount of size in our tree that it takes and to reduce ongoing
merge maintenance.
-shpopen.c: int32_t instead of int32 was used to eliminate clang warnings.
-shpopen.c: include <stdint.h> for MSVC.
</pre>
The DBFAddField() function is used to add new fields to an existing xBase
- file opened with DBFOpen(), or created with DBFCreate(). Note that fields
- can only be added to xBase files with no records, though this is limitation
- of this API, not of the file format.<p>
+ file opened with DBFOpen(), or created with DBFCreate().<p>
The DBFAddField() return value is the field number of the new field, or
-1 if the addition of the field failed.<p>
/******************************************************************************
- * $Id: dbfopen.c,v 1.89 2011-07-24 05:59:25 fwarmerdam Exp $
+ * $Id: dbfopen.c,v 1.92 2016-12-05 18:44:08 erouault Exp $
*
* Project: Shapelib
* Purpose: Implementation of .dbf access API documented in dbf_api.html.
*
******************************************************************************
* Copyright (c) 1999, Frank Warmerdam
+ * Copyright (c) 2012-2013, Even Rouault <even dot rouault at mines-paris dot org>
*
* This software is available under the following "MIT Style" license,
- * or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
+ * or at the option of the licensee under the LGPL (see COPYING). This
* option is discussed in more detail in shapelib.html.
*
* --
- *
+ *
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
******************************************************************************
*
* $Log: dbfopen.c,v $
+ * Revision 1.92 2016-12-05 18:44:08 erouault
+ * * dbfopen.c, shapefil.h: write DBF end-of-file character 0x1A by default.
+ * This behaviour can be controlled with the DBFSetWriteEndOfFileChar()
+ * function.
+ *
+ * Revision 1.91 2016-12-05 12:44:05 erouault
+ * * Major overhaul of Makefile build system to use autoconf/automake.
+ *
+ * * Warning fixes in contrib/
+ *
+ * Revision 1.90 2016-12-04 15:30:15 erouault
+ * * shpopen.c, dbfopen.c, shptree.c, shapefil.h: resync with
+ * GDAL Shapefile driver. Mostly cleanups. SHPObject and DBFInfo
+ * structures extended with new members. New functions:
+ * DBFSetLastModifiedDate, SHPOpenLLEx, SHPRestoreSHX,
+ * SHPSetFastModeReadObject
+ *
+ * * sbnsearch.c: new file to implement original ESRI .sbn spatial
+ * index reading. (no write support). New functions:
+ * SBNOpenDiskTree, SBNCloseDiskTree, SBNSearchDiskTree,
+ * SBNSearchDiskTreeInteger, SBNSearchFreeIds
+ *
+ * * Makefile, makefile.vc, CMakeLists.txt, shapelib.def: updates
+ * with new file and symbols.
+ *
+ * * commit: helper script to cvs commit
+ *
* Revision 1.89 2011-07-24 05:59:25 fwarmerdam
* minimize use of CPLError in favor of SAHooks.Error()
*
*
* Revision 1.77 2007/12/15 20:25:21 bram
* dbfopen.c now reads the Code Page information from the DBF file, and exports
- * this information as a string through the DBFGetCodePage function. This is
- * either the number from the LDID header field ("LDID/<number>") or as the
+ * this information as a string through the DBFGetCodePage function. This is
+ * either the number from the LDID header field ("LDID/<number>") or as the
* content of an accompanying .CPG file. When creating a DBF file, the code can
* be set using DBFCreateEx.
*
#include <ctype.h>
#include <string.h>
-SHP_CVSID("$Id: dbfopen.c,v 1.89 2011-07-24 05:59:25 fwarmerdam Exp $")
+#ifdef USE_CPL
+#include "cpl_string.h"
+#else
+
+#if defined(_MSC_VER)
+# if _MSC_VER < 1900
+# define snprintf _snprintf
+# endif
+#elif defined(WIN32) || defined(_WIN32)
+# ifndef snprintf
+# define snprintf _snprintf
+# endif
+#endif
+
+#define CPLsprintf sprintf
+#define CPLsnprintf snprintf
+#endif
+
+SHP_CVSID("$Id: dbfopen.c,v 1.92 2016-12-05 18:44:08 erouault Exp $")
#ifndef FALSE
# define FALSE 0
# define TRUE 1
#endif
+/* File header size */
+#define XBASE_FILEHDR_SZ 32
+
+#define HEADER_RECORD_TERMINATOR 0x0D
+
+/* See http://www.manmrk.net/tutorials/database/xbase/dbf.html */
+#define END_OF_FILE_CHARACTER 0x1A
+
+#ifdef USE_CPL
+CPL_INLINE static void CPL_IGNORE_RET_VAL_INT(CPL_UNUSED int unused) {}
+#else
+#define CPL_IGNORE_RET_VAL_INT(x) x
+#endif
+
/************************************************************************/
/* SfRealloc() */
/* */
static void DBFWriteHeader(DBFHandle psDBF)
{
- unsigned char abyHeader[XBASE_FLDHDR_SZ];
- int i;
+ unsigned char abyHeader[XBASE_FILEHDR_SZ] = { 0 };
if( !psDBF->bNoHeader )
return;
/* -------------------------------------------------------------------- */
/* Initialize the file header information. */
/* -------------------------------------------------------------------- */
- for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
- abyHeader[i] = 0;
-
abyHeader[0] = 0x03; /* memo field? - just copying */
- /* write out a dummy date */
- abyHeader[1] = 95; /* YY */
- abyHeader[2] = 7; /* MM */
- abyHeader[3] = 26; /* DD */
+ /* write out update date */
+ abyHeader[1] = (unsigned char) psDBF->nUpdateYearSince1900;
+ abyHeader[2] = (unsigned char) psDBF->nUpdateMonth;
+ abyHeader[3] = (unsigned char) psDBF->nUpdateDay;
/* record count preset at zero */
abyHeader[8] = (unsigned char) (psDBF->nHeaderLength % 256);
abyHeader[9] = (unsigned char) (psDBF->nHeaderLength / 256);
-
+
abyHeader[10] = (unsigned char) (psDBF->nRecordLength % 256);
abyHeader[11] = (unsigned char) (psDBF->nRecordLength / 256);
/* descriptions. */
/* -------------------------------------------------------------------- */
psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
- psDBF->sHooks.FWrite( abyHeader, XBASE_FLDHDR_SZ, 1, psDBF->fp );
- psDBF->sHooks.FWrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields,
+ psDBF->sHooks.FWrite( abyHeader, XBASE_FILEHDR_SZ, 1, psDBF->fp );
+ psDBF->sHooks.FWrite( psDBF->pszHeader, XBASE_FLDHDR_SZ, psDBF->nFields,
psDBF->fp );
/* -------------------------------------------------------------------- */
/* Write out the newline character if there is room for it. */
/* -------------------------------------------------------------------- */
- if( psDBF->nHeaderLength > 32*psDBF->nFields + 32 )
+ if( psDBF->nHeaderLength > XBASE_FLDHDR_SZ*psDBF->nFields +
+ XBASE_FLDHDR_SZ )
{
char cNewline;
- cNewline = 0x0d;
+ cNewline = HEADER_RECORD_TERMINATOR;
psDBF->sHooks.FWrite( &cNewline, 1, 1, psDBF->fp );
}
+
+/* -------------------------------------------------------------------- */
+/* If the file is new, add a EOF character. */
+/* -------------------------------------------------------------------- */
+ if( psDBF->nRecords == 0 && psDBF->bWriteEndOfFileChar )
+ {
+ char ch = END_OF_FILE_CHARACTER;
+
+ psDBF->sHooks.FWrite( &ch, 1, 1, psDBF->fp );
+ }
}
/************************************************************************/
{
psDBF->bCurrentRecordModified = FALSE;
- nRecordOffset =
- psDBF->nRecordLength * (SAOffset) psDBF->nCurrentRecord
+ nRecordOffset =
+ psDBF->nRecordLength * (SAOffset) psDBF->nCurrentRecord
+ psDBF->nHeaderLength;
- if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ) != 0
- || psDBF->sHooks.FWrite( psDBF->pszCurrentRecord,
- psDBF->nRecordLength,
+ if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 ) != 0
+ || psDBF->sHooks.FWrite( psDBF->pszCurrentRecord,
+ psDBF->nRecordLength,
1, psDBF->fp ) != 1 )
{
char szMessage[128];
- sprintf( szMessage, "Failure writing DBF record %d.",
+ snprintf( szMessage, sizeof(szMessage), "Failure writing DBF record %d.",
psDBF->nCurrentRecord );
psDBF->sHooks.Error( szMessage );
return FALSE;
}
+
+ if( psDBF->nCurrentRecord == psDBF->nRecords - 1 )
+ {
+ if( psDBF->bWriteEndOfFileChar )
+ {
+ char ch = END_OF_FILE_CHARACTER;
+ psDBF->sHooks.FWrite( &ch, 1, 1, psDBF->fp );
+ }
+ }
}
return TRUE;
if( !DBFFlushRecord( psDBF ) )
return FALSE;
- nRecordOffset =
+ nRecordOffset =
psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
if( psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, SEEK_SET ) != 0 )
{
char szMessage[128];
- sprintf( szMessage, "fseek(%ld) failed on DBF file.\n",
+ snprintf( szMessage, sizeof(szMessage), "fseek(%ld) failed on DBF file.",
(long) nRecordOffset );
psDBF->sHooks.Error( szMessage );
return FALSE;
}
- if( psDBF->sHooks.FRead( psDBF->pszCurrentRecord,
+ if( psDBF->sHooks.FRead( psDBF->pszCurrentRecord,
psDBF->nRecordLength, 1, psDBF->fp ) != 1 )
{
char szMessage[128];
- sprintf( szMessage, "fread(%d) failed on DBF file.\n",
+ snprintf( szMessage, sizeof(szMessage), "fread(%d) failed on DBF file.",
psDBF->nRecordLength );
psDBF->sHooks.Error( szMessage );
return FALSE;
DBFUpdateHeader( DBFHandle psDBF )
{
- unsigned char abyFileHeader[32];
+ unsigned char abyFileHeader[XBASE_FILEHDR_SZ];
if( psDBF->bNoHeader )
DBFWriteHeader( psDBF );
- DBFFlushRecord( psDBF );
+ if( !DBFFlushRecord( psDBF ) )
+ return;
psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
- psDBF->sHooks.FRead( abyFileHeader, 32, 1, psDBF->fp );
-
+ psDBF->sHooks.FRead( abyFileHeader, sizeof(abyFileHeader), 1, psDBF->fp );
+
+ abyFileHeader[1] = (unsigned char) psDBF->nUpdateYearSince1900;
+ abyFileHeader[2] = (unsigned char) psDBF->nUpdateMonth;
+ abyFileHeader[3] = (unsigned char) psDBF->nUpdateDay;
abyFileHeader[4] = (unsigned char) (psDBF->nRecords % 256);
abyFileHeader[5] = (unsigned char) ((psDBF->nRecords/256) % 256);
abyFileHeader[6] = (unsigned char) ((psDBF->nRecords/(256*256)) % 256);
abyFileHeader[7] = (unsigned char) ((psDBF->nRecords/(256*256*256)) % 256);
-
+
psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
- psDBF->sHooks.FWrite( abyFileHeader, 32, 1, psDBF->fp );
+ psDBF->sHooks.FWrite( abyFileHeader, sizeof(abyFileHeader), 1, psDBF->fp );
psDBF->sHooks.FFlush( psDBF->fp );
}
+/************************************************************************/
+/* DBFSetLastModifiedDate() */
+/************************************************************************/
+
+void SHPAPI_CALL
+DBFSetLastModifiedDate( DBFHandle psDBF, int nYYSince1900, int nMM, int nDD )
+{
+ psDBF->nUpdateYearSince1900 = nYYSince1900;
+ psDBF->nUpdateMonth = nMM;
+ psDBF->nUpdateDay = nDD;
+}
+
/************************************************************************/
/* DBFOpen() */
/* */
/* Open a .dbf file. */
/************************************************************************/
-
+
DBFHandle SHPAPI_CALL
DBFOpen( const char * pszFilename, const char * pszAccess )
/* */
/* Open a .dbf file. */
/************************************************************************/
-
+
DBFHandle SHPAPI_CALL
DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
int nFields, nHeadLen, iField, i;
char *pszBasename, *pszFullname;
int nBufSize = 500;
+ size_t nFullnameLen;
/* -------------------------------------------------------------------- */
/* We only allow the access strings "rb" and "r+". */
/* -------------------------------------------------------------------- */
- if( strcmp(pszAccess,"r") != 0 && strcmp(pszAccess,"r+") != 0
+ if( strcmp(pszAccess,"r") != 0 && strcmp(pszAccess,"r+") != 0
&& strcmp(pszAccess,"rb") != 0 && strcmp(pszAccess,"rb+") != 0
&& strcmp(pszAccess,"r+b") != 0 )
return( NULL );
if( strcmp(pszAccess,"r") == 0 )
pszAccess = "rb";
-
+
if( strcmp(pszAccess,"r+") == 0 )
pszAccess = "rb+";
/* -------------------------------------------------------------------- */
pszBasename = (char *) malloc(strlen(pszFilename)+5);
strcpy( pszBasename, pszFilename );
- for( i = strlen(pszBasename)-1;
+ for( i = (int)strlen(pszBasename)-1;
i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
&& pszBasename[i] != '\\';
i-- ) {}
if( pszBasename[i] == '.' )
pszBasename[i] = '\0';
- pszFullname = (char *) malloc(strlen(pszBasename) + 5);
- sprintf( pszFullname, "%s.dbf", pszBasename );
-
+ nFullnameLen = strlen(pszBasename) + 5;
+ pszFullname = (char *) malloc(nFullnameLen);
+ snprintf( pszFullname, nFullnameLen, "%s.dbf", pszBasename );
+
psDBF = (DBFHandle) calloc( 1, sizeof(DBFInfo) );
psDBF->fp = psHooks->FOpen( pszFullname, pszAccess );
memcpy( &(psDBF->sHooks), psHooks, sizeof(SAHooks) );
if( psDBF->fp == NULL )
{
- sprintf( pszFullname, "%s.DBF", pszBasename );
+ snprintf( pszFullname, nFullnameLen, "%s.DBF", pszBasename );
psDBF->fp = psDBF->sHooks.FOpen(pszFullname, pszAccess );
}
- sprintf( pszFullname, "%s.cpg", pszBasename );
+ snprintf( pszFullname, nFullnameLen, "%s.cpg", pszBasename );
pfCPG = psHooks->FOpen( pszFullname, "r" );
if( pfCPG == NULL )
{
- sprintf( pszFullname, "%s.CPG", pszBasename );
+ snprintf( pszFullname, nFullnameLen, "%s.CPG", pszBasename );
pfCPG = psHooks->FOpen( pszFullname, "r" );
}
free( pszBasename );
free( pszFullname );
-
+
if( psDBF->fp == NULL )
{
free( psDBF );
/* Read Table Header info */
/* -------------------------------------------------------------------- */
pabyBuf = (unsigned char *) malloc(nBufSize);
- if( psDBF->sHooks.FRead( pabyBuf, 32, 1, psDBF->fp ) != 1 )
+ if( psDBF->sHooks.FRead( pabyBuf, XBASE_FILEHDR_SZ, 1, psDBF->fp ) != 1 )
{
psDBF->sHooks.FClose( psDBF->fp );
if( pfCPG ) psDBF->sHooks.FClose( pfCPG );
return NULL;
}
- psDBF->nRecords =
- pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256;
+ DBFSetLastModifiedDate(psDBF, pabyBuf[1], pabyBuf[2], pabyBuf[3]);
+
+ psDBF->nRecords =
+ pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + (pabyBuf[7] & 0x7f) *256*256*256;
psDBF->nHeaderLength = nHeadLen = pabyBuf[8] + pabyBuf[9]*256;
psDBF->nRecordLength = pabyBuf[10] + pabyBuf[11]*256;
psDBF->iLanguageDriver = pabyBuf[29];
- if (nHeadLen < 32)
+ if (psDBF->nRecordLength == 0 || nHeadLen < XBASE_FILEHDR_SZ)
{
psDBF->sHooks.FClose( psDBF->fp );
if( pfCPG ) psDBF->sHooks.FClose( pfCPG );
return NULL;
}
- psDBF->nFields = nFields = (nHeadLen - 32) / 32;
+ psDBF->nFields = nFields = (nHeadLen - XBASE_FILEHDR_SZ) / XBASE_FLDHDR_SZ;
psDBF->pszCurrentRecord = (char *) malloc(psDBF->nRecordLength);
}
if( psDBF->pszCodePage == NULL && pabyBuf[29] != 0 )
{
- sprintf( (char *) pabyBuf, "LDID/%d", psDBF->iLanguageDriver );
+ snprintf( (char *) pabyBuf, nBufSize, "LDID/%d", psDBF->iLanguageDriver );
psDBF->pszCodePage = (char *) malloc(strlen((char*)pabyBuf) + 1);
strcpy( psDBF->pszCodePage, (char *) pabyBuf );
}
/* -------------------------------------------------------------------- */
/* Read in Field Definitions */
/* -------------------------------------------------------------------- */
-
+
pabyBuf = (unsigned char *) SfRealloc(pabyBuf,nHeadLen);
psDBF->pszHeader = (char *) pabyBuf;
- psDBF->sHooks.FSeek( psDBF->fp, 32, 0 );
- if( psDBF->sHooks.FRead( pabyBuf, nHeadLen-32, 1, psDBF->fp ) != 1 )
+ psDBF->sHooks.FSeek( psDBF->fp, XBASE_FILEHDR_SZ, 0 );
+ if( psDBF->sHooks.FRead( pabyBuf, nHeadLen-XBASE_FILEHDR_SZ, 1,
+ psDBF->fp ) != 1 )
{
psDBF->sHooks.FClose( psDBF->fp );
free( pabyBuf );
{
unsigned char *pabyFInfo;
- pabyFInfo = pabyBuf+iField*32;
+ pabyFInfo = pabyBuf+iField*XBASE_FLDHDR_SZ;
if( pabyFInfo[11] == 'N' || pabyFInfo[11] == 'F' )
{
if( iField == 0 )
psDBF->panFieldOffset[iField] = 1;
else
- psDBF->panFieldOffset[iField] =
+ psDBF->panFieldOffset[iField] =
psDBF->panFieldOffset[iField-1] + psDBF->panFieldSize[iField-1];
}
+ DBFSetWriteEndOfFileChar( psDBF, TRUE );
+
return( psDBF );
}
if( psDBF->bNoHeader )
DBFWriteHeader( psDBF );
- DBFFlushRecord( psDBF );
+ CPL_IGNORE_RET_VAL_INT(DBFFlushRecord( psDBF ));
/* -------------------------------------------------------------------- */
/* Update last access date, and number of records if we have */
char *pszFullname, *pszBasename;
int i, ldid = -1;
char chZero = '\0';
+ size_t nFullnameLen;
/* -------------------------------------------------------------------- */
/* Compute the base (layer) name. If there is any extension */
/* -------------------------------------------------------------------- */
pszBasename = (char *) malloc(strlen(pszFilename)+5);
strcpy( pszBasename, pszFilename );
- for( i = strlen(pszBasename)-1;
+ for( i = (int)strlen(pszBasename)-1;
i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
&& pszBasename[i] != '\\';
i-- ) {}
if( pszBasename[i] == '.' )
pszBasename[i] = '\0';
- pszFullname = (char *) malloc(strlen(pszBasename) + 5);
- sprintf( pszFullname, "%s.dbf", pszBasename );
+ nFullnameLen = strlen(pszBasename) + 5;
+ pszFullname = (char *) malloc(nFullnameLen);
+ snprintf( pszFullname, nFullnameLen, "%s.dbf", pszBasename );
/* -------------------------------------------------------------------- */
/* Create the file. */
/* -------------------------------------------------------------------- */
fp = psHooks->FOpen( pszFullname, "wb" );
- if( fp == NULL ) {
- free(pszBasename);
- free(pszFullname);
+ if( fp == NULL )
+ {
+ free( pszBasename );
+ free( pszFullname );
return( NULL );
}
-
+
psHooks->FWrite( &chZero, 1, 1, fp );
psHooks->FClose( fp );
fp = psHooks->FOpen( pszFullname, "rb+" );
- if( fp == NULL ) {
- free(pszBasename);
- free(pszFullname);
+ if( fp == NULL )
+ {
+ free( pszBasename );
+ free( pszFullname );
return( NULL );
}
-
- sprintf( pszFullname, "%s.cpg", pszBasename );
+ snprintf( pszFullname, nFullnameLen, "%s.cpg", pszBasename );
if( pszCodePage != NULL )
{
if( strncmp( pszCodePage, "LDID/", 5 ) == 0 )
psDBF->nRecords = 0;
psDBF->nFields = 0;
psDBF->nRecordLength = 1;
- psDBF->nHeaderLength = 33;
-
+ psDBF->nHeaderLength = XBASE_FILEHDR_SZ + 1; /* + 1 for HEADER_RECORD_TERMINATOR */
+
psDBF->panFieldOffset = NULL;
psDBF->panFieldSize = NULL;
psDBF->panFieldDecimals = NULL;
psDBF->pszCodePage = (char * ) malloc( strlen(pszCodePage) + 1 );
strcpy( psDBF->pszCodePage, pszCodePage );
}
+ DBFSetLastModifiedDate(psDBF, 95, 7, 26); /* dummy date */
+
+ DBFSetWriteEndOfFileChar(psDBF, TRUE);
return( psDBF );
}
/************************************************************************/
int SHPAPI_CALL
-DBFAddField(DBFHandle psDBF, const char * pszFieldName,
+DBFAddField(DBFHandle psDBF, const char * pszFieldName,
DBFFieldType eType, int nWidth, int nDecimals )
{
else
chNativeType = 'N';
- return DBFAddNativeFieldType( psDBF, pszFieldName, chNativeType,
+ return DBFAddNativeFieldType( psDBF, pszFieldName, chNativeType,
nWidth, nDecimals );
}
/************************************************************************/
int SHPAPI_CALL
-DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName,
+DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName,
char chType, int nWidth, int nDecimals )
{
if( !DBFFlushRecord( psDBF ) )
return -1;
+ if( psDBF->nHeaderLength + XBASE_FLDHDR_SZ > 65535 )
+ {
+ char szMessage[128];
+ snprintf( szMessage, sizeof(szMessage),
+ "Cannot add field %s. Header length limit reached "
+ "(max 65535 bytes, 2046 fields).",
+ pszFieldName );
+ psDBF->sHooks.Error( szMessage );
+ return -1;
+ }
+
/* -------------------------------------------------------------------- */
/* Do some checking to ensure we can add records to this file. */
/* -------------------------------------------------------------------- */
if( nWidth < 1 )
return -1;
- if( nWidth > 255 )
- nWidth = 255;
+ if( nWidth > XBASE_FLD_MAX_WIDTH )
+ nWidth = XBASE_FLD_MAX_WIDTH;
+
+ if( psDBF->nRecordLength + nWidth > 65535 )
+ {
+ char szMessage[128];
+ snprintf( szMessage, sizeof(szMessage),
+ "Cannot add field %s. Record length limit reached "
+ "(max 65535 bytes).",
+ pszFieldName );
+ psDBF->sHooks.Error( szMessage );
+ return -1;
+ }
nOldRecordLength = psDBF->nRecordLength;
nOldHeaderLength = psDBF->nHeaderLength;
/* -------------------------------------------------------------------- */
psDBF->nFields++;
- psDBF->panFieldOffset = (int *)
+ psDBF->panFieldOffset = (int *)
SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
- psDBF->panFieldSize = (int *)
+ psDBF->panFieldSize = (int *)
SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
- psDBF->panFieldDecimals = (int *)
+ psDBF->panFieldDecimals = (int *)
SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
- psDBF->pachFieldType = (char *)
+ psDBF->pachFieldType = (char *)
SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
/* Extend the required header information. */
/* -------------------------------------------------------------------- */
- psDBF->nHeaderLength += 32;
+ psDBF->nHeaderLength += XBASE_FLDHDR_SZ;
psDBF->bUpdated = FALSE;
- psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
+ psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,
+ psDBF->nFields*XBASE_FLDHDR_SZ);
- pszFInfo = psDBF->pszHeader + 32 * (psDBF->nFields-1);
+ pszFInfo = psDBF->pszHeader + XBASE_FLDHDR_SZ * (psDBF->nFields-1);
- for( i = 0; i < 32; i++ )
+ for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
pszFInfo[i] = '\0';
- if( (int) strlen(pszFieldName) < 10 )
- strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
- else
- strncpy( pszFInfo, pszFieldName, 10);
+ strncpy( pszFInfo, pszFieldName, XBASE_FLDNAME_LEN_WRITE );
pszFInfo[11] = psDBF->pachFieldType[psDBF->nFields-1];
pszFInfo[16] = (unsigned char) nWidth;
pszFInfo[17] = (unsigned char) nDecimals;
}
-
+
/* -------------------------------------------------------------------- */
/* Make the current record buffer appropriately larger. */
/* -------------------------------------------------------------------- */
psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
}
+ if( psDBF->bWriteEndOfFileChar )
+ {
+ char ch = END_OF_FILE_CHARACTER;
+
+ nRecordOffset =
+ psDBF->nRecordLength * (SAOffset) psDBF->nRecords + psDBF->nHeaderLength;
+
+ psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
+ psDBF->sHooks.FWrite( &ch, 1, 1, psDBF->fp );
+ }
+
/* free record */
free(pszRecord);
psDBF->nCurrentRecord = -1;
psDBF->bCurrentRecordModified = FALSE;
+ psDBF->bUpdated = TRUE;
return( psDBF->nFields-1 );
}
/* -------------------------------------------------------------------- */
/* Extract the requested field. */
/* -------------------------------------------------------------------- */
- strncpy( psDBF->pszWorkField,
+ memcpy( psDBF->pszWorkField,
((const char *) pabyRec) + psDBF->panFieldOffset[iField],
psDBF->panFieldSize[iField] );
psDBF->pszWorkField[psDBF->panFieldSize[iField]] = '\0';
/* -------------------------------------------------------------------- */
/* Decode the field. */
/* -------------------------------------------------------------------- */
- if( chReqType == 'N' )
+ if( chReqType == 'I' )
{
- psDBF->dfDoubleField = psDBF->sHooks.Atof(psDBF->pszWorkField);
+ psDBF->fieldValue.nIntField = atoi(psDBF->pszWorkField);
- pReturnField = &(psDBF->dfDoubleField);
+ pReturnField = &(psDBF->fieldValue.nIntField);
+ }
+ else if( chReqType == 'N' )
+ {
+ psDBF->fieldValue.dfDoubleField = psDBF->sHooks.Atof(psDBF->pszWorkField);
+
+ pReturnField = &(psDBF->fieldValue.dfDoubleField);
}
/* -------------------------------------------------------------------- */
*pchDst = '\0';
}
#endif
-
+
return( pReturnField );
}
DBFReadIntegerAttribute( DBFHandle psDBF, int iRecord, int iField )
{
- double *pdValue;
+ int *pnValue;
- pdValue = (double *) DBFReadAttribute( psDBF, iRecord, iField, 'N' );
+ pnValue = (int *) DBFReadAttribute( psDBF, iRecord, iField, 'I' );
- if( pdValue == NULL )
+ if( pnValue == NULL )
return 0;
else
- return( (int) *pdValue );
+ return( *pnValue );
}
/************************************************************************/
/* DBFGetFieldInfo() */
/* */
/* Return any requested information about the field. */
+/* pszFieldName must be at least XBASE_FLDNAME_LEN_READ+1 (=12) */
+/* bytes long. */
/************************************************************************/
DBFFieldType SHPAPI_CALL
{
int i;
- strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*32, 11 );
- pszFieldName[11] = '\0';
- for( i = 10; i > 0 && pszFieldName[i] == ' '; i-- )
+ strncpy( pszFieldName, (char *) psDBF->pszHeader+iField*XBASE_FLDHDR_SZ,
+ XBASE_FLDNAME_LEN_READ );
+ pszFieldName[XBASE_FLDNAME_LEN_READ] = '\0';
+ for( i = XBASE_FLDNAME_LEN_READ - 1; i > 0 && pszFieldName[i] == ' '; i-- )
pszFieldName[i] = '\0';
}
if ( psDBF->pachFieldType[iField] == 'L' )
return( FTLogical);
- else if( psDBF->pachFieldType[iField] == 'N'
+ else if( psDBF->pachFieldType[iField] == 'N'
|| psDBF->pachFieldType[iField] == 'F' )
{
- if( psDBF->panFieldDecimals[iField] > 0
- || psDBF->panFieldSize[iField] > 10 )
+ if( psDBF->panFieldDecimals[iField] > 0
+ || psDBF->panFieldSize[iField] >= 10 )
return( FTDouble );
else
return( FTInteger );
{
int i, j, nRetResult = TRUE;
unsigned char *pabyRec;
- char szSField[400], szFormat[20];
+ char szSField[XBASE_FLD_MAX_WIDTH+1], szFormat[20];
/* -------------------------------------------------------------------- */
/* Is this a valid record? */
case 'D':
case 'N':
case 'F':
- if( psDBF->panFieldDecimals[iField] == 0 )
- {
- int nWidth = psDBF->panFieldSize[iField];
+ {
+ int nWidth = psDBF->panFieldSize[iField];
- if( (int) sizeof(szSField)-2 < nWidth )
- nWidth = sizeof(szSField)-2;
+ if( (int) sizeof(szSField)-2 < nWidth )
+ nWidth = sizeof(szSField)-2;
- sprintf( szFormat, "%%%dd", nWidth );
- sprintf(szSField, szFormat, (int) *((double *) pValue) );
- if( (int)strlen(szSField) > psDBF->panFieldSize[iField] )
- {
- szSField[psDBF->panFieldSize[iField]] = '\0';
- nRetResult = FALSE;
- }
-
- strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
- szSField, strlen(szSField) );
- }
- else
- {
- int nWidth = psDBF->panFieldSize[iField];
-
- if( (int) sizeof(szSField)-2 < nWidth )
- nWidth = sizeof(szSField)-2;
-
- sprintf( szFormat, "%%%d.%df",
- nWidth, psDBF->panFieldDecimals[iField] );
- sprintf(szSField, szFormat, *((double *) pValue) );
- if( (int) strlen(szSField) > psDBF->panFieldSize[iField] )
- {
- szSField[psDBF->panFieldSize[iField]] = '\0';
- nRetResult = FALSE;
- }
- strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
- szSField, strlen(szSField) );
- }
- break;
+ snprintf( szFormat, sizeof(szFormat), "%%%d.%df",
+ nWidth, psDBF->panFieldDecimals[iField] );
+ CPLsnprintf(szSField, sizeof(szSField), szFormat, *((double *) pValue) );
+ if( (int) strlen(szSField) > psDBF->panFieldSize[iField] )
+ {
+ szSField[psDBF->panFieldSize[iField]] = '\0';
+ nRetResult = FALSE;
+ }
+ strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
+ szSField, strlen(szSField) );
+ break;
+ }
case 'L':
- if (psDBF->panFieldSize[iField] >= 1 &&
+ if (psDBF->panFieldSize[iField] >= 1 &&
(*(char*)pValue == 'F' || *(char*)pValue == 'T'))
*(pabyRec+psDBF->panFieldOffset[iField]) = *(char*)pValue;
break;
{
memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
psDBF->panFieldSize[iField] );
- j = strlen((char *) pValue);
+ j = (int)strlen((char *) pValue);
}
strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
{
memset( pabyRec+psDBF->panFieldOffset[iField], ' ',
psDBF->panFieldSize[iField] );
- j = strlen((char *) pValue);
+ j = (int)strlen((char *) pValue);
}
strncpy((char *) (pabyRec+psDBF->panFieldOffset[iField]),
/************************************************************************/
DBFHandle SHPAPI_CALL
-DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename )
+DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename )
{
DBFHandle newDBF;
newDBF = DBFCreateEx ( pszFilename, psDBF->pszCodePage );
- if ( newDBF == NULL ) return ( NULL );
-
+ if ( newDBF == NULL ) return ( NULL );
+
newDBF->nFields = psDBF->nFields;
newDBF->nRecordLength = psDBF->nRecordLength;
newDBF->nHeaderLength = psDBF->nHeaderLength;
-
- newDBF->pszHeader = (char *) malloc ( newDBF->nHeaderLength );
- memcpy ( newDBF->pszHeader, psDBF->pszHeader, newDBF->nHeaderLength );
-
- newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields );
+
+ if( psDBF->pszHeader )
+ {
+ newDBF->pszHeader = (char *) malloc ( XBASE_FLDHDR_SZ * psDBF->nFields );
+ memcpy ( newDBF->pszHeader, psDBF->pszHeader, XBASE_FLDHDR_SZ * psDBF->nFields );
+ }
+
+ newDBF->panFieldOffset = (int *) malloc ( sizeof(int) * psDBF->nFields );
memcpy ( newDBF->panFieldOffset, psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
newDBF->panFieldSize = (int *) malloc ( sizeof(int) * psDBF->nFields );
memcpy ( newDBF->panFieldSize, psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
newDBF->bNoHeader = TRUE;
newDBF->bUpdated = TRUE;
-
+ newDBF->bWriteEndOfFileChar = psDBF->bWriteEndOfFileChar;
+
DBFWriteHeader ( newDBF );
DBFClose ( newDBF );
-
+
newDBF = DBFOpen ( pszFilename, "rb+" );
+ newDBF->bWriteEndOfFileChar = psDBF->bWriteEndOfFileChar;
return ( newDBF );
}
static void str_to_upper (char *string)
{
int len;
- short i = -1;
+ int i = -1;
- len = strlen (string);
+ len = (int)strlen (string);
while (++i < len)
if (isalpha(string[i]) && islower(string[i]))
DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName)
{
- char name[12], name1[12], name2[12];
+ char name[XBASE_FLDNAME_LEN_READ+1],
+ name1[XBASE_FLDNAME_LEN_READ+1],
+ name2[XBASE_FLDNAME_LEN_READ+1];
int i;
- strncpy(name1, pszFieldName,11);
- name1[11] = '\0';
+ strncpy(name1, pszFieldName,XBASE_FLDNAME_LEN_READ);
+ name1[XBASE_FLDNAME_LEN_READ] = '\0';
str_to_upper(name1);
for( i = 0; i < DBFGetFieldCount(psDBF); i++ )
{
DBFGetFieldInfo( psDBF, i, name, NULL, NULL );
- strncpy(name2,name,11);
+ strncpy(name2,name,XBASE_FLDNAME_LEN_READ);
+ name2[XBASE_FLDNAME_LEN_READ] = '\0';
str_to_upper(name2);
- if(!strncmp(name1,name2,10))
+ if(!strcmp(name1,name2))
return(i);
}
return(-1);
/* DBFMarkRecordDeleted() */
/************************************************************************/
-int SHPAPI_CALL DBFMarkRecordDeleted( DBFHandle psDBF, int iShape,
+int SHPAPI_CALL DBFMarkRecordDeleted( DBFHandle psDBF, int iShape,
int bIsDeleted )
{
/* -------------------------------------------------------------------- */
if( bIsDeleted )
chNewFlag = '*';
- else
+ else
chNewFlag = ' ';
if( psDBF->pszCurrentRecord[0] != chNewFlag )
/* resize fields arrays */
psDBF->nFields--;
- psDBF->panFieldOffset = (int *)
+ psDBF->panFieldOffset = (int *)
SfRealloc( psDBF->panFieldOffset, sizeof(int) * psDBF->nFields );
- psDBF->panFieldSize = (int *)
+ psDBF->panFieldSize = (int *)
SfRealloc( psDBF->panFieldSize, sizeof(int) * psDBF->nFields );
- psDBF->panFieldDecimals = (int *)
+ psDBF->panFieldDecimals = (int *)
SfRealloc( psDBF->panFieldDecimals, sizeof(int) * psDBF->nFields );
- psDBF->pachFieldType = (char *)
+ psDBF->pachFieldType = (char *)
SfRealloc( psDBF->pachFieldType, sizeof(char) * psDBF->nFields );
/* update header information */
- psDBF->nHeaderLength -= 32;
+ psDBF->nHeaderLength -= XBASE_FLDHDR_SZ;
psDBF->nRecordLength -= nDeletedFieldSize;
/* overwrite field information in header */
- memmove(psDBF->pszHeader + iField*32,
- psDBF->pszHeader + (iField+1)*32,
- sizeof(char) * (psDBF->nFields - iField)*32);
+ memmove(psDBF->pszHeader + iField*XBASE_FLDHDR_SZ,
+ psDBF->pszHeader + (iField+1)*XBASE_FLDHDR_SZ,
+ sizeof(char) * (psDBF->nFields - iField)*XBASE_FLDHDR_SZ);
- psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,psDBF->nFields*32);
+ psDBF->pszHeader = (char *) SfRealloc(psDBF->pszHeader,
+ psDBF->nFields*XBASE_FLDHDR_SZ);
/* update size of current record appropriately */
psDBF->pszCurrentRecord = (char *) SfRealloc(psDBF->pszCurrentRecord,
/* shift records to their new positions */
for (iRecord = 0; iRecord < psDBF->nRecords; iRecord++)
{
- nRecordOffset =
+ nRecordOffset =
nOldRecordLength * (SAOffset) iRecord + nOldHeaderLength;
/* load record */
psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
psDBF->sHooks.FRead( pszRecord, nOldRecordLength, 1, psDBF->fp );
- nRecordOffset =
+ nRecordOffset =
psDBF->nRecordLength * (SAOffset) iRecord + psDBF->nHeaderLength;
/* move record in two steps */
}
+ if( psDBF->bWriteEndOfFileChar )
+ {
+ char ch = END_OF_FILE_CHARACTER;
+ psDBF->sHooks.FWrite( &ch, 1, 1, psDBF->fp );
+ }
+
/* TODO: truncate file */
/* free record */
psDBF->nCurrentRecord = -1;
psDBF->bCurrentRecordModified = FALSE;
+ psDBF->bUpdated = TRUE;
return TRUE;
}
if( !DBFFlushRecord( psDBF ) )
return FALSE;
- panFieldOffsetNew = (int *) malloc(sizeof(int) * psDBF->nFields);
- panFieldSizeNew = (int *) malloc(sizeof(int) * psDBF->nFields);
- panFieldDecimalsNew = (int *) malloc(sizeof(int) * psDBF->nFields);
- pachFieldTypeNew = (char *) malloc(sizeof(char) * psDBF->nFields);
- pszHeaderNew = (char*) malloc(sizeof(char) * 32 * psDBF->nFields);
+ /* a simple malloc() would be enough, but calloc() helps clang static analyzer */
+ panFieldOffsetNew = (int *) calloc(sizeof(int), psDBF->nFields);
+ panFieldSizeNew = (int *) calloc(sizeof(int), psDBF->nFields);
+ panFieldDecimalsNew = (int *) calloc(sizeof(int), psDBF->nFields);
+ pachFieldTypeNew = (char *) calloc(sizeof(char), psDBF->nFields);
+ pszHeaderNew = (char*) malloc(sizeof(char) * XBASE_FLDHDR_SZ *
+ psDBF->nFields);
/* shuffle fields definitions */
for(i=0; i < psDBF->nFields; i++)
panFieldSizeNew[i] = psDBF->panFieldSize[panMap[i]];
panFieldDecimalsNew[i] = psDBF->panFieldDecimals[panMap[i]];
pachFieldTypeNew[i] = psDBF->pachFieldType[panMap[i]];
- memcpy(pszHeaderNew + i * 32,
- psDBF->pszHeader + panMap[i] * 32, 32);
+ memcpy(pszHeaderNew + i * XBASE_FLDHDR_SZ,
+ psDBF->pszHeader + panMap[i] * XBASE_FLDHDR_SZ, XBASE_FLDHDR_SZ);
}
panFieldOffsetNew[0] = 1;
for(i=1; i < psDBF->nFields; i++)
psDBF->nCurrentRecord = -1;
psDBF->bCurrentRecordModified = FALSE;
+ psDBF->bUpdated = TRUE;
return TRUE;
}
int nOffset;
int nOldWidth;
int nOldRecordLength;
- int nRecordOffset;
+ SAOffset nRecordOffset;
char* pszFInfo;
char chOldType;
int bIsNULL;
if( nWidth < 1 )
return -1;
- if( nWidth > 255 )
- nWidth = 255;
+ if( nWidth > XBASE_FLD_MAX_WIDTH )
+ nWidth = XBASE_FLD_MAX_WIDTH;
/* -------------------------------------------------------------------- */
/* Assign the new field information fields. */
/* -------------------------------------------------------------------- */
/* Update the header information. */
/* -------------------------------------------------------------------- */
- pszFInfo = psDBF->pszHeader + 32 * iField;
+ pszFInfo = psDBF->pszHeader + XBASE_FLDHDR_SZ * iField;
- for( i = 0; i < 32; i++ )
+ for( i = 0; i < XBASE_FLDHDR_SZ; i++ )
pszFInfo[i] = '\0';
- if( (int) strlen(pszFieldName) < 10 )
- strncpy( pszFInfo, pszFieldName, strlen(pszFieldName));
- else
- strncpy( pszFInfo, pszFieldName, 10);
+ strncpy( pszFInfo, pszFieldName, XBASE_FLDNAME_LEN_WRITE );
pszFInfo[11] = psDBF->pachFieldType[iField];
char* pszRecord = (char *) malloc(sizeof(char) * nOldRecordLength);
char* pszOldField = (char *) malloc(sizeof(char) * (nOldWidth + 1));
+ /* cppcheck-suppress uninitdata */
pszOldField[nOldWidth] = 0;
/* move records to their new positions */
psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
}
+ if( psDBF->bWriteEndOfFileChar )
+ {
+ char ch = END_OF_FILE_CHARACTER;
+
+ nRecordOffset =
+ psDBF->nRecordLength * (SAOffset) psDBF->nRecords + psDBF->nHeaderLength;
+
+ psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
+ psDBF->sHooks.FWrite( &ch, 1, 1, psDBF->fp );
+ }
+ /* TODO: truncate file */
+
free(pszRecord);
free(pszOldField);
}
char* pszRecord = (char *) malloc(sizeof(char) * psDBF->nRecordLength);
char* pszOldField = (char *) malloc(sizeof(char) * (nOldWidth + 1));
+ /* cppcheck-suppress uninitdata */
pszOldField[nOldWidth] = 0;
/* move records to their new positions */
psDBF->sHooks.FWrite( pszRecord, psDBF->nRecordLength, 1, psDBF->fp );
}
+ if( psDBF->bWriteEndOfFileChar )
+ {
+ char ch = END_OF_FILE_CHARACTER;
+
+ nRecordOffset =
+ psDBF->nRecordLength * (SAOffset) psDBF->nRecords + psDBF->nHeaderLength;
+
+ psDBF->sHooks.FSeek( psDBF->fp, nRecordOffset, 0 );
+ psDBF->sHooks.FWrite( &ch, 1, 1, psDBF->fp );
+ }
+
free(pszRecord);
free(pszOldField);
}
psDBF->nCurrentRecord = -1;
psDBF->bCurrentRecordModified = FALSE;
+ psDBF->bUpdated = TRUE;
return TRUE;
}
+
+/************************************************************************/
+/* DBFSetWriteEndOfFileChar() */
+/************************************************************************/
+
+void SHPAPI_CALL DBFSetWriteEndOfFileChar( DBFHandle psDBF, int bWriteFlag )
+{
+ psDBF->bWriteEndOfFileChar = bWriteFlag;
+}
/******************************************************************************
- * $Id: safileio.c,v 1.4 2008-01-16 20:05:14 bram Exp $
+ * $Id: safileio.c,v 1.5 2016-12-05 12:44:05 erouault Exp $
*
* Project: Shapelib
* Purpose: Default implementation of file io based on stdio.
* Copyright (c) 2007, Frank Warmerdam
*
* This software is available under the following "MIT Style" license,
- * or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
+ * or at the option of the licensee under the LGPL (see COPYING). This
* option is discussed in more detail in shapelib.html.
*
* --
******************************************************************************
*
* $Log: safileio.c,v $
+ * Revision 1.5 2016-12-05 12:44:05 erouault
+ * * Major overhaul of Makefile build system to use autoconf/automake.
+ *
+ * * Warning fixes in contrib/
+ *
* Revision 1.4 2008-01-16 20:05:14 bram
* Add file hooks that accept UTF-8 encoded filenames on some platforms. Use SASetupUtf8Hooks
* tosetup the hooks and check SHPAPI_UTF8_HOOKS for its availability. Currently, this
#include <string.h>
#include <stdio.h>
-SHP_CVSID("$Id: safileio.c,v 1.4 2008-01-16 20:05:14 bram Exp $");
+SHP_CVSID("$Id: safileio.c,v 1.5 2016-12-05 12:44:05 erouault Exp $");
#ifdef SHPAPI_UTF8_HOOKS
# ifdef SHPAPI_WINDOWS
#define SHAPEFILE_H_INCLUDED
/******************************************************************************
- * $Id: shapefil.h,v 1.52 2011-12-11 22:26:46 fwarmerdam Exp $
+ * $Id: shapefil.h,v 1.55 2016-12-05 18:44:08 erouault Exp $
*
* Project: Shapelib
* Purpose: Primary include file for Shapelib.
*
******************************************************************************
* Copyright (c) 1999, Frank Warmerdam
+ * Copyright (c) 2012-2016, Even Rouault <even dot rouault at mines-paris dot org>
*
* This software is available under the following "MIT Style" license,
- * or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
+ * or at the option of the licensee under the LGPL (see COPYING). This
* option is discussed in more detail in shapelib.html.
*
* --
- *
+ *
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
******************************************************************************
*
* $Log: shapefil.h,v $
+ * Revision 1.55 2016-12-05 18:44:08 erouault
+ * * dbfopen.c, shapefil.h: write DBF end-of-file character 0x1A by default.
+ * This behaviour can be controlled with the DBFSetWriteEndOfFileChar()
+ * function.
+ *
+ * Revision 1.54 2016-12-05 12:44:05 erouault
+ * * Major overhaul of Makefile build system to use autoconf/automake.
+ *
+ * * Warning fixes in contrib/
+ *
+ * Revision 1.53 2016-12-04 15:30:15 erouault
+ * * shpopen.c, dbfopen.c, shptree.c, shapefil.h: resync with
+ * GDAL Shapefile driver. Mostly cleanups. SHPObject and DBFInfo
+ * structures extended with new members. New functions:
+ * DBFSetLastModifiedDate, SHPOpenLLEx, SHPRestoreSHX,
+ * SHPSetFastModeReadObject
+ *
+ * * sbnsearch.c: new file to implement original ESRI .sbn spatial
+ * index reading. (no write support). New functions:
+ * SBNOpenDiskTree, SBNCloseDiskTree, SBNSearchDiskTree,
+ * SBNSearchDiskTreeInteger, SBNSearchFreeIds
+ *
+ * * Makefile, makefile.vc, CMakeLists.txt, shapelib.def: updates
+ * with new file and symbols.
+ *
+ * * commit: helper script to cvs commit
+ *
* Revision 1.52 2011-12-11 22:26:46 fwarmerdam
* upgrade .qix access code to use SAHooks (gdal #3365)
*
#include <dbmalloc.h>
#endif
+#ifdef USE_CPL
+#include "cpl_conv.h"
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
/* is disabled. */
/* -------------------------------------------------------------------- */
#define DISABLE_MULTIPATCH_MEASURE
-
+
/* -------------------------------------------------------------------- */
/* SHPAPI_CALL */
/* */
/* #define SHPAPI_CALL __declspec(dllexport) __stdcall */
/* #define SHPAPI_CALL1 __declspec(dllexport) * __stdcall */
/* */
-/* The complexity of the situtation is partly caused by the */
+/* The complexity of the situation is partly caused by the */
/* peculiar requirement of Visual C++ that __stdcall appear */
/* after any "*"'s in the return value of a function while the */
/* __declspec(dllexport) must appear before them. */
#ifndef SHPAPI_CALL1
# define SHPAPI_CALL1(x) x SHPAPI_CALL
#endif
-
+
/* -------------------------------------------------------------------- */
/* Macros for controlling CVSID and ensuring they don't appear */
/* as unreferenced variables resulting in lots of warnings. */
/* -------------------------------------------------------------------- */
#ifndef DISABLE_CVSID
# if defined(__GNUC__) && __GNUC__ >= 4
-# define SHP_CVSID(string) static char cpl_cvsid[] __attribute__((used)) = string;
+# define SHP_CVSID(string) static const char cpl_cvsid[] __attribute__((used)) = string;
# else
-# define SHP_CVSID(string) static char cpl_cvsid[] = string; \
-static char *cvsid_aw() { return( cvsid_aw() ? ((char *) NULL) : cpl_cvsid ); }
+# define SHP_CVSID(string) static const char cpl_cvsid[] = string; \
+static const char *cvsid_aw() { return( cvsid_aw() ? NULL : cpl_cvsid ); }
# endif
#else
# define SHP_CVSID(string)
/* UTF-8 encoded filenames Unicode filenames */
/* -------------------------------------------------------------------- */
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
-# define SHPAPI_WINDOWS
-# define SHPAPI_UTF8_HOOKS
+# define SHPAPI_WINDOWS
+# define SHPAPI_UTF8_HOOKS
#endif
/* -------------------------------------------------------------------- */
/************************************************************************/
/* SHP Support. */
/************************************************************************/
-typedef struct
+typedef struct tagSHPObject SHPObject;
+
+typedef struct
{
SAHooks sHooks;
SAFile fpSHP;
- SAFile fpSHX;
+ SAFile fpSHX;
+
+ int nShapeType; /* SHPT_* */
- int nShapeType; /* SHPT_* */
-
- unsigned int nFileSize; /* SHP file */
+ unsigned int nFileSize; /* SHP file */
int nRecords;
- int nMaxRecords;
- unsigned int *panRecOffset;
- unsigned int *panRecSize;
+ int nMaxRecords;
+ unsigned int*panRecOffset;
+ unsigned int *panRecSize;
- double adBoundsMin[4];
- double adBoundsMax[4];
+ double adBoundsMin[4];
+ double adBoundsMax[4];
- int bUpdated;
+ int bUpdated;
unsigned char *pabyRec;
int nBufSize;
+
+ int bFastModeReadObject;
+ unsigned char *pabyObjectBuf;
+ int nObjectBufSize;
+ SHPObject* psCachedObject;
} SHPInfo;
typedef SHPInfo * SHPHandle;
/* -------------------------------------------------------------------- */
/* Shape types (nSHPType) */
/* -------------------------------------------------------------------- */
-#define SHPT_NULL 0
-#define SHPT_POINT 1
-#define SHPT_ARC 3
-#define SHPT_POLYGON 5
-#define SHPT_MULTIPOINT 8
-#define SHPT_POINTZ 11
-#define SHPT_ARCZ 13
-#define SHPT_POLYGONZ 15
+#define SHPT_NULL 0
+#define SHPT_POINT 1
+#define SHPT_ARC 3
+#define SHPT_POLYGON 5
+#define SHPT_MULTIPOINT 8
+#define SHPT_POINTZ 11
+#define SHPT_ARCZ 13
+#define SHPT_POLYGONZ 15
#define SHPT_MULTIPOINTZ 18
-#define SHPT_POINTM 21
-#define SHPT_ARCM 23
-#define SHPT_POLYGONM 25
+#define SHPT_POINTM 21
+#define SHPT_ARCM 23
+#define SHPT_POLYGONM 25
#define SHPT_MULTIPOINTM 28
#define SHPT_MULTIPATCH 31
-
/* -------------------------------------------------------------------- */
/* Part types - everything but SHPT_MULTIPATCH just uses */
/* SHPP_RING. */
/* -------------------------------------------------------------------- */
-#define SHPP_TRISTRIP 0
-#define SHPP_TRIFAN 1
-#define SHPP_OUTERRING 2
-#define SHPP_INNERRING 3
-#define SHPP_FIRSTRING 4
-#define SHPP_RING 5
+#define SHPP_TRISTRIP 0
+#define SHPP_TRIFAN 1
+#define SHPP_OUTERRING 2
+#define SHPP_INNERRING 3
+#define SHPP_FIRSTRING 4
+#define SHPP_RING 5
/* -------------------------------------------------------------------- */
/* SHPObject - represents on shape (without attributes) read */
/* from the .shp file. */
/* -------------------------------------------------------------------- */
-typedef struct
+struct tagSHPObject
{
- int nSHPType;
+ int nSHPType;
+
+ int nShapeId; /* -1 is unknown/unassigned */
- int nShapeId; /* -1 is unknown/unassigned */
+ int nParts;
+ int *panPartStart;
+ int *panPartType;
- int nParts;
- int *panPartStart;
- int *panPartType;
-
- int nVertices;
- double *padfX;
- double *padfY;
- double *padfZ;
- double *padfM;
+ int nVertices;
+ double *padfX;
+ double *padfY;
+ double *padfZ;
+ double *padfM;
- double dfXMin;
- double dfYMin;
- double dfZMin;
- double dfMMin;
+ double dfXMin;
+ double dfYMin;
+ double dfZMin;
+ double dfMMin;
- double dfXMax;
- double dfYMax;
- double dfZMax;
- double dfMMax;
+ double dfXMax;
+ double dfYMax;
+ double dfZMax;
+ double dfMMax;
- int bMeasureIsUsed;
-} SHPObject;
+ int bMeasureIsUsed;
+ int bFastModeReadObject;
+};
/* -------------------------------------------------------------------- */
/* SHP API Prototypes */
SHPHandle SHPAPI_CALL
SHPOpen( const char * pszShapeFile, const char * pszAccess );
SHPHandle SHPAPI_CALL
- SHPOpenLL( const char *pszShapeFile, const char *pszAccess,
+ SHPOpenLL( const char *pszShapeFile, const char *pszAccess,
SAHooks *psHooks );
+SHPHandle SHPAPI_CALL
+ SHPOpenLLEx( const char *pszShapeFile, const char *pszAccess,
+ SAHooks *psHooks, int bRestoreSHX );
+
+int SHPAPI_CALL
+ SHPRestoreSHX( const char *pszShapeFile, const char *pszAccess,
+ SAHooks *psHooks );
+
+/* If setting bFastMode = TRUE, the content of SHPReadObject() is owned by the SHPHandle. */
+/* So you cannot have 2 valid instances of SHPReadObject() simultaneously. */
+/* The SHPObject padfZ and padfM members may be NULL depending on the geometry */
+/* type. It is illegal to free at hand any of the pointer members of the SHPObject structure */
+void SHPAPI_CALL SHPSetFastModeReadObject( SHPHandle hSHP, int bFastMode );
+
SHPHandle SHPAPI_CALL
SHPCreate( const char * pszShapeFile, int nShapeType );
SHPHandle SHPAPI_CALL
void SHPAPI_CALL
SHPComputeExtents( SHPObject * psObject );
SHPObject SHPAPI_CALL1(*)
- SHPCreateObject( int nSHPType, int nShapeId, int nParts,
+ SHPCreateObject( int nSHPType, int nShapeId, int nParts,
const int * panPartStart, const int * panPartType,
- int nVertices,
+ int nVertices,
const double * padfX, const double * padfY,
const double * padfZ, const double * padfM );
SHPObject SHPAPI_CALL1(*)
SHPCreateSimpleObject( int nSHPType, int nVertices,
- const double * padfX,
- const double * padfY,
+ const double * padfX,
+ const double * padfY,
const double * padfZ );
int SHPAPI_CALL
/* -------------------------------------------------------------------- */
/* this can be two or four for binary or quad tree */
-#define MAX_SUBNODE 4
+#define MAX_SUBNODE 4
/* upper limit of tree levels for automatic estimation */
#define MAX_DEFAULT_TREE_DEPTH 12
typedef struct shape_tree_node
{
/* region covered by this node */
- double adfBoundsMin[4];
- double adfBoundsMax[4];
+ double adfBoundsMin[4];
+ double adfBoundsMax[4];
/* list of shapes stored at this node. The papsShapeObj pointers
or the whole list can be NULL */
- int nShapeCount;
- int *panShapeIds;
+ int nShapeCount;
+ int *panShapeIds;
SHPObject **papsShapeObj;
- int nSubNodes;
+ int nSubNodes;
struct shape_tree_node *apsSubNode[MAX_SUBNODE];
-
+
} SHPTreeNode;
typedef struct
{
SHPHandle hSHP;
-
- int nMaxDepth;
- int nDimension;
+
+ int nMaxDepth;
+ int nDimension;
int nTotalCount;
-
- SHPTreeNode *psRoot;
+
+ SHPTreeNode *psRoot;
} SHPTree;
SHPTree SHPAPI_CALL1(*)
SHPCreateTree( SHPHandle hSHP, int nDimension, int nMaxDepth,
double *padfBoundsMin, double *padfBoundsMax );
-void SHPAPI_CALL
+void SHPAPI_CALL
SHPDestroyTree( SHPTree * hTree );
-int SHPAPI_CALL
+int SHPAPI_CALL
SHPWriteTree( SHPTree *hTree, const char * pszFilename );
-int SHPAPI_CALL
+int SHPAPI_CALL
SHPTreeAddShapeId( SHPTree * hTree, SHPObject * psObject );
-int SHPAPI_CALL
+int SHPAPI_CALL
SHPTreeRemoveShapeId( SHPTree * hTree, int nShapeId );
-void SHPAPI_CALL
+void SHPAPI_CALL
SHPTreeTrimExtraNodes( SHPTree * hTree );
-int SHPAPI_CALL1(*)
+int SHPAPI_CALL1(*)
SHPTreeFindLikelyShapes( SHPTree * hTree,
double * padfBoundsMin,
double * padfBoundsMax,
int * );
-int SHPAPI_CALL
+int SHPAPI_CALL
SHPCheckBoundsOverlap( double *, double *, double *, double *, int );
-int SHPAPI_CALL1(*)
-SHPSearchDiskTree( FILE *fp,
+int SHPAPI_CALL1(*)
+SHPSearchDiskTree( FILE *fp,
double *padfBoundsMin, double *padfBoundsMax,
int *pnShapeCount );
-
typedef struct SHPDiskTreeInfo* SHPTreeDiskHandle;
SHPTreeDiskHandle SHPAPI_CALL
void SHPAPI_CALL
SHPCloseDiskTree( SHPTreeDiskHandle hDiskTree );
-int SHPAPI_CALL1(*)
-SHPSearchDiskTreeEx( SHPTreeDiskHandle hDiskTree,
- double *padfBoundsMin, double *padfBoundsMax,
- int *pnShapeCount );
+int SHPAPI_CALL1(*)
+SHPSearchDiskTreeEx( SHPTreeDiskHandle hDiskTree,
+ double *padfBoundsMin, double *padfBoundsMax,
+ int *pnShapeCount );
int SHPAPI_CALL
SHPWriteTreeLL(SHPTree *hTree, const char *pszFilename, SAHooks *psHooks );
+/* -------------------------------------------------------------------- */
+/* SBN Search API */
+/* -------------------------------------------------------------------- */
+
+typedef struct SBNSearchInfo* SBNSearchHandle;
+
+SBNSearchHandle SHPAPI_CALL
+ SBNOpenDiskTree( const char* pszSBNFilename,
+ SAHooks *psHooks );
+
+void SHPAPI_CALL
+ SBNCloseDiskTree( SBNSearchHandle hSBN );
+
+int SHPAPI_CALL1(*)
+SBNSearchDiskTree( SBNSearchHandle hSBN,
+ double *padfBoundsMin, double *padfBoundsMax,
+ int *pnShapeCount );
+
+int SHPAPI_CALL1(*)
+SBNSearchDiskTreeInteger( SBNSearchHandle hSBN,
+ int bMinX, int bMinY, int bMaxX, int bMaxY,
+ int *pnShapeCount );
+
+void SHPAPI_CALL SBNSearchFreeIds( int* panShapeId );
+
/************************************************************************/
/* DBF Support. */
/************************************************************************/
-typedef struct
+typedef struct
{
SAHooks sHooks;
- SAFile fp;
+ SAFile fp;
int nRecords;
- int nRecordLength;
- int nHeaderLength;
- int nFields;
- int *panFieldOffset;
- int *panFieldSize;
- int *panFieldDecimals;
- char *pachFieldType;
+ int nRecordLength; /* Must fit on uint16 */
+ int nHeaderLength; /* File header length (32) + field
+ descriptor length + spare space.
+ Must fit on uint16 */
+ int nFields;
+ int *panFieldOffset;
+ int *panFieldSize;
+ int *panFieldDecimals;
+ char *pachFieldType;
- char *pszHeader;
+ char *pszHeader; /* Field descriptors */
- int nCurrentRecord;
- int bCurrentRecordModified;
- char *pszCurrentRecord;
+ int nCurrentRecord;
+ int bCurrentRecordModified;
+ char *pszCurrentRecord;
int nWorkFieldLength;
char *pszWorkField;
-
- int bNoHeader;
- int bUpdated;
- double dfDoubleField;
+ int bNoHeader;
+ int bUpdated;
+
+ union
+ {
+ double dfDoubleField;
+ int nIntField;
+ } fieldValue;
int iLanguageDriver;
char *pszCodePage;
+
+ int nUpdateYearSince1900; /* 0-255 */
+ int nUpdateMonth; /* 1-12 */
+ int nUpdateDay; /* 1-31 */
+
+ int bWriteEndOfFileChar; /* defaults to TRUE */
} DBFInfo;
typedef DBFInfo * DBFHandle;
FTInvalid
} DBFFieldType;
-#define XBASE_FLDHDR_SZ 32
-
+/* Field descriptor/header size */
+#define XBASE_FLDHDR_SZ 32
+/* Shapelib read up to 11 characters, even if only 10 should normally be used */
+#define XBASE_FLDNAME_LEN_READ 11
+/* On writing, we limit to 10 characters */
+#define XBASE_FLDNAME_LEN_WRITE 10
+/* Normally only 254 characters should be used. We tolerate 255 historically */
+#define XBASE_FLD_MAX_WIDTH 255
DBFHandle SHPAPI_CALL
DBFOpen( const char * pszDBFFile, const char * pszAccess );
DBFHandle SHPAPI_CALL
DBFCreateLL( const char * pszDBFFile, const char * pszCodePage, SAHooks *psHooks );
-int SHPAPI_CALL
+int SHPAPI_CALL
DBFGetFieldCount( DBFHandle psDBF );
-int SHPAPI_CALL
+int SHPAPI_CALL
DBFGetRecordCount( DBFHandle psDBF );
-int SHPAPI_CALL
+int SHPAPI_CALL
DBFAddField( DBFHandle hDBF, const char * pszFieldName,
DBFFieldType eType, int nWidth, int nDecimals );
-int SHPAPI_CALL
+int SHPAPI_CALL
DBFAddNativeFieldType( DBFHandle hDBF, const char * pszFieldName,
char chType, int nWidth, int nDecimals );
-int SHPAPI_CALL
+int SHPAPI_CALL
DBFDeleteField( DBFHandle hDBF, int iField );
int SHPAPI_CALL
char chType, int nWidth, int nDecimals );
DBFFieldType SHPAPI_CALL
- DBFGetFieldInfo( DBFHandle psDBF, int iField,
+ DBFGetFieldInfo( DBFHandle psDBF, int iField,
char * pszFieldName, int * pnWidth, int * pnDecimals );
int SHPAPI_CALL
DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName);
-int SHPAPI_CALL
+int SHPAPI_CALL
DBFReadIntegerAttribute( DBFHandle hDBF, int iShape, int iField );
-double SHPAPI_CALL
+double SHPAPI_CALL
DBFReadDoubleAttribute( DBFHandle hDBF, int iShape, int iField );
const char SHPAPI_CALL1(*)
DBFReadStringAttribute( DBFHandle hDBF, int iShape, int iField );
const char SHPAPI_CALL1(*)
DBFReadLogicalAttribute( DBFHandle hDBF, int iShape, int iField );
-int SHPAPI_CALL
+int SHPAPI_CALL
DBFIsAttributeNULL( DBFHandle hDBF, int iShape, int iField );
int SHPAPI_CALL
- DBFWriteIntegerAttribute( DBFHandle hDBF, int iShape, int iField,
+ DBFWriteIntegerAttribute( DBFHandle hDBF, int iShape, int iField,
int nFieldValue );
int SHPAPI_CALL
DBFWriteDoubleAttribute( DBFHandle hDBF, int iShape, int iField,
int SHPAPI_CALL
DBFWriteLogicalAttribute( DBFHandle hDBF, int iShape, int iField,
- const char lFieldValue);
+ const char lFieldValue);
int SHPAPI_CALL
DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
void * pValue );
DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple );
int SHPAPI_CALL DBFIsRecordDeleted( DBFHandle psDBF, int iShape );
-int SHPAPI_CALL DBFMarkRecordDeleted( DBFHandle psDBF, int iShape,
+int SHPAPI_CALL DBFMarkRecordDeleted( DBFHandle psDBF, int iShape,
int bIsDeleted );
DBFHandle SHPAPI_CALL
DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename );
-
-void SHPAPI_CALL
+
+void SHPAPI_CALL
DBFClose( DBFHandle hDBF );
void SHPAPI_CALL
DBFUpdateHeader( DBFHandle hDBF );
-char SHPAPI_CALL
+char SHPAPI_CALL
DBFGetNativeFieldType( DBFHandle hDBF, int iField );
const char SHPAPI_CALL1(*)
DBFGetCodePage(DBFHandle psDBF );
+void SHPAPI_CALL
+ DBFSetLastModifiedDate( DBFHandle psDBF, int nYYSince1900, int nMM, int nDD );
+
+void SHPAPI_CALL DBFSetWriteEndOfFileChar( DBFHandle psDBF, int bWriteFlag );
+
#ifdef __cplusplus
}
#endif
<html>
<head>
-<title>Shapefile C Library V1.2</title>
-<link href="http://www.maptools.org/maptools.css" rel="stylesheet" type="text/css">
+<title>Shapefile C Library</title>
+<link href="maptools.css" rel="stylesheet" type="text/css">
</head>
<body>
-<h1>Shapefile C Library V1.2</h1>
+<h1>Shapefile C Library</h1>
<h2>Purpose</h2>
<h2>Download</h2>
Source code, and some other odds and ends can be downloaded from
-<a href="http://download.osgeo.org/shapelib">http://download.osgeo.org/shapelib</a> or <a href="http://shapelib.maptools.org/dl">http://shapelib.maptools.org/dl</a>.<p>
+<a href="http://download.osgeo.org/shapelib">http://download.osgeo.org/shapelib</a>.<p>
Shapelib is available for anonymous CVS access:
</body>
</html>
-
-
-
/******************************************************************************
- * $Id: shpopen.c,v 1.73 2012-01-24 22:33:01 fwarmerdam Exp $
+ * $Id: shpopen.c,v 1.76 2017-09-10 10:11:36 erouault Exp $
*
* Project: Shapelib
* Purpose: Implementation of core Shapefile read/write functions.
*
******************************************************************************
* Copyright (c) 1999, 2001, Frank Warmerdam
+ * Copyright (c) 2011-2013, Even Rouault <even dot rouault at mines-paris dot org>
*
* This software is available under the following "MIT Style" license,
- * or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
+ * or at the option of the licensee under the LGPL (see COPYING). This
* option is discussed in more detail in shapelib.html.
*
* --
- *
+ *
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
******************************************************************************
*
* $Log: shpopen.c,v $
+ * Revision 1.76 2017-09-10 10:11:36 erouault
+ * * shpopen.c: resync with GDAL copy. Make sure to zero terminate all
+ * error messages. And fix regression regarding re-writing the last shape
+ * of a file (https://trac.osgeo.org/gdal/ticket/7031)
+ *
+ * Revision 1.75 2016-12-05 12:44:05 erouault
+ * * Major overhaul of Makefile build system to use autoconf/automake.
+ *
+ * * Warning fixes in contrib/
+ *
+ * Revision 1.74 2016-12-04 15:30:15 erouault
+ * * shpopen.c, dbfopen.c, shptree.c, shapefil.h: resync with
+ * GDAL Shapefile driver. Mostly cleanups. SHPObject and DBFInfo
+ * structures extended with new members. New functions:
+ * DBFSetLastModifiedDate, SHPOpenLLEx, SHPRestoreSHX,
+ * SHPSetFastModeReadObject
+ *
+ * * sbnsearch.c: new file to implement original ESRI .sbn spatial
+ * index reading. (no write support). New functions:
+ * SBNOpenDiskTree, SBNCloseDiskTree, SBNSearchDiskTree,
+ * SBNSearchDiskTreeInteger, SBNSearchFreeIds
+ *
+ * * Makefile, makefile.vc, CMakeLists.txt, shapelib.def: updates
+ * with new file and symbols.
+ *
+ * * commit: helper script to cvs commit
+ *
* Revision 1.73 2012-01-24 22:33:01 fwarmerdam
* fix memory leak on failure to open .shp (gdal #4410)
*
* avoid c++ comments
*
* Revision 1.38 2002/05/07 16:43:39 warmerda
- * Removed debugging printf.
+ * Removed debugging printf()
*
* Revision 1.37 2002/04/10 17:35:22 warmerda
* fixed bug in ring reversal code
* move pabyRec into SHPInfo for thread safety
*
* Revision 1.33 2001/07/03 12:18:15 warmerda
- * Improved cleanup if SHX not found, provied by Riccardo Cohen.
+ * Improved cleanup if SHX not found, provided by Riccardo Cohen.
*
* Revision 1.32 2001/06/22 01:58:07 warmerda
* be more careful about establishing initial bounds in face of NULL shapes
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
-// GPSBabel-local: add stdint for MSVC.
-#include <stdint.h>
+#include <errno.h>
-SHP_CVSID("$Id: shpopen.c,v 1.73 2012-01-24 22:33:01 fwarmerdam Exp $")
+SHP_CVSID("$Id: shpopen.c,v 1.76 2017-09-10 10:11:36 erouault Exp $")
typedef unsigned char uchar;
# define MAX(a,b) ((a>b) ? a : b)
#endif
-#if defined(WIN32) || defined(_WIN32)
+#ifndef USE_CPL
+#if defined(_MSC_VER)
+# if _MSC_VER < 1900
+# define snprintf _snprintf
+# endif
+#elif defined(WIN32) || defined(_WIN32)
# ifndef snprintf
# define snprintf _snprintf
# endif
#endif
+#endif
-static int bBigEndian;
+#ifndef CPL_UNUSED
+#if defined(__GNUC__) && __GNUC__ >= 4
+# define CPL_UNUSED __attribute((__unused__))
+#else
+# define CPL_UNUSED
+#endif
+#endif
+#if defined(CPL_LSB)
+#define bBigEndian FALSE
+#elif defined(CPL_MSB)
+#define bBigEndian TRUE
+#else
+static int bBigEndian;
+#endif
/************************************************************************/
/* SwapWord() */
void SHPAPI_CALL SHPWriteHeader( SHPHandle psSHP )
{
- uchar abyHeader[100];
+ uchar abyHeader[100] = { 0 };
int i;
int32 i32;
double dValue;
int32 *panSHX;
-
+
if (psSHP->fpSHX == NULL)
{
psSHP->sHooks.Error( "SHPWriteHeader failed : SHX file is closed");
/* -------------------------------------------------------------------- */
/* Prepare header block for .shp file. */
/* -------------------------------------------------------------------- */
- for( i = 0; i < 100; i++ )
- abyHeader[i] = 0;
abyHeader[2] = 0x27; /* magic cookie */
abyHeader[3] = 0x0a;
i32 = psSHP->nFileSize/2; /* file size */
ByteCopy( &i32, abyHeader+24, 4 );
if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
-
+
i32 = 1000; /* version */
ByteCopy( &i32, abyHeader+28, 4 );
if( bBigEndian ) SwapWord( 4, abyHeader+28 );
-
+
i32 = psSHP->nShapeType; /* shape type */
ByteCopy( &i32, abyHeader+32, 4 );
if( bBigEndian ) SwapWord( 4, abyHeader+32 );
/* -------------------------------------------------------------------- */
/* Write .shp file header. */
/* -------------------------------------------------------------------- */
- if( psSHP->sHooks.FSeek( psSHP->fpSHP, 0, 0 ) != 0
+ if( psSHP->sHooks.FSeek( psSHP->fpSHP, 0, 0 ) != 0
|| psSHP->sHooks.FWrite( abyHeader, 100, 1, psSHP->fpSHP ) != 1 )
{
- psSHP->sHooks.Error( "Failure writing .shp header" );
+ char szErrorMsg[200];
+
+ snprintf( szErrorMsg, sizeof(szErrorMsg),
+ "Failure writing .shp header: %s", strerror(errno) );
+ szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
+ psSHP->sHooks.Error( szErrorMsg );
return;
}
i32 = (psSHP->nRecords * 2 * sizeof(int32) + 100)/2; /* file size */
ByteCopy( &i32, abyHeader+24, 4 );
if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
-
- if( psSHP->sHooks.FSeek( psSHP->fpSHX, 0, 0 ) != 0
+
+ if( psSHP->sHooks.FSeek( psSHP->fpSHX, 0, 0 ) != 0
|| psSHP->sHooks.FWrite( abyHeader, 100, 1, psSHP->fpSHX ) != 1 )
{
- psSHP->sHooks.Error( "Failure writing .shx header" );
+ char szErrorMsg[200];
+
+ snprintf( szErrorMsg, sizeof(szErrorMsg),
+ "Failure writing .shx header: %s", strerror(errno) );
+ szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
+ psSHP->sHooks.Error( szErrorMsg );
+
return;
}
/* Write out the .shx contents. */
/* -------------------------------------------------------------------- */
panSHX = (int32 *) malloc(sizeof(int32) * 2 * psSHP->nRecords);
+ if( panSHX == NULL )
+ {
+ psSHP->sHooks.Error( "Failure allocatin panSHX" );
+ return;
+ }
for( i = 0; i < psSHP->nRecords; i++ )
{
if( !bBigEndian ) SwapWord( 4, panSHX+i*2+1 );
}
- if( (int)psSHP->sHooks.FWrite( panSHX, sizeof(int32)*2, psSHP->nRecords, psSHP->fpSHX )
+ if( (int)psSHP->sHooks.FWrite( panSHX, sizeof(int32)*2, psSHP->nRecords, psSHP->fpSHX )
!= psSHP->nRecords )
{
- psSHP->sHooks.Error( "Failure writing .shx contents" );
+ char szErrorMsg[200];
+
+ snprintf( szErrorMsg, sizeof(szErrorMsg),
+ "Failure writing .shx contents: %s", strerror(errno) );
+ szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
+ psSHP->sHooks.Error( szErrorMsg );
}
free( panSHX );
/* Open the .shp and .shx files based on the basename of the */
/* files or either file name. */
/************************************************************************/
-
+
SHPHandle SHPAPI_CALL
SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
{
- char *pszFullname, *pszBasename;
- SHPHandle psSHP;
-
- uchar *pabyBuf;
- int i;
- double dValue;
-
+ char *pszFullname, *pszBasename;
+ SHPHandle psSHP;
+
+ uchar *pabyBuf;
+ int i;
+ double dValue;
+ int bLazySHXLoading = FALSE;
+ size_t nFullnameLen;
+
/* -------------------------------------------------------------------- */
/* Ensure the access string is one of the legal ones. We */
/* ensure the result string indicates binary to avoid common */
|| strcmp(pszAccess,"r+") == 0 )
pszAccess = "r+b";
else
+ {
+ bLazySHXLoading = strchr(pszAccess, 'l') != NULL;
pszAccess = "rb";
-
+ }
+
/* -------------------------------------------------------------------- */
-/* Establish the byte order on this machine. */
+/* Establish the byte order on this machine. */
/* -------------------------------------------------------------------- */
+#if !defined(bBigEndian)
i = 1;
if( *((uchar *) &i) == 1 )
bBigEndian = FALSE;
else
bBigEndian = TRUE;
+#endif
/* -------------------------------------------------------------------- */
-/* Initialize the info structure. */
+/* Initialize the info structure. */
/* -------------------------------------------------------------------- */
psSHP = (SHPHandle) calloc(sizeof(SHPInfo),1);
memcpy( &(psSHP->sHooks), psHooks, sizeof(SAHooks) );
/* -------------------------------------------------------------------- */
-/* Compute the base (layer) name. If there is any extension */
-/* on the passed in filename we will strip it off. */
+/* Compute the base (layer) name. If there is any extension */
+/* on the passed in filename we will strip it off. */
/* -------------------------------------------------------------------- */
pszBasename = (char *) malloc(strlen(pszLayer)+5);
strcpy( pszBasename, pszLayer );
- for( i = strlen(pszBasename)-1;
+ for( i = (int)strlen(pszBasename)-1;
i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
&& pszBasename[i] != '\\';
i-- ) {}
pszBasename[i] = '\0';
/* -------------------------------------------------------------------- */
-/* Open the .shp and .shx files. Note that files pulled from */
-/* a PC to Unix with upper case filenames won't work! */
+/* Open the .shp and .shx files. Note that files pulled from */
+/* a PC to Unix with upper case filenames won't work! */
/* -------------------------------------------------------------------- */
- pszFullname = (char *) malloc(strlen(pszBasename) + 5);
- sprintf( pszFullname, "%s.shp", pszBasename ) ;
+ nFullnameLen = strlen(pszBasename) + 5;
+ pszFullname = (char *) malloc(nFullnameLen);
+ snprintf( pszFullname, nFullnameLen, "%s.shp", pszBasename ) ;
psSHP->fpSHP = psSHP->sHooks.FOpen(pszFullname, pszAccess );
if( psSHP->fpSHP == NULL )
{
- sprintf( pszFullname, "%s.SHP", pszBasename );
+ snprintf( pszFullname, nFullnameLen, "%s.SHP", pszBasename );
psSHP->fpSHP = psSHP->sHooks.FOpen(pszFullname, pszAccess );
}
-
+
if( psSHP->fpSHP == NULL )
{
- char *pszMessage = (char *) malloc(strlen(pszBasename)*2+256);
- sprintf( pszMessage, "Unable to open %s.shp or %s.SHP.",
+ size_t nMessageLen = strlen(pszBasename)*2+256;
+ char *pszMessage = (char *) malloc(nMessageLen);
+ snprintf( pszMessage, nMessageLen, "Unable to open %s.shp or %s.SHP.",
pszBasename, pszBasename );
psHooks->Error( pszMessage );
free( pszMessage );
return NULL;
}
- sprintf( pszFullname, "%s.shx", pszBasename );
+ snprintf( pszFullname, nFullnameLen, "%s.shx", pszBasename );
psSHP->fpSHX = psSHP->sHooks.FOpen(pszFullname, pszAccess );
if( psSHP->fpSHX == NULL )
{
- sprintf( pszFullname, "%s.SHX", pszBasename );
+ snprintf( pszFullname, nFullnameLen, "%s.SHX", pszBasename );
psSHP->fpSHX = psSHP->sHooks.FOpen(pszFullname, pszAccess );
}
-
+
if( psSHP->fpSHX == NULL )
{
- char *pszMessage = (char *) malloc(strlen(pszBasename)*2+256);
- sprintf( pszMessage, "Unable to open %s.shx or %s.SHX.",
+ size_t nMessageLen = strlen(pszBasename)*2+256;
+ char *pszMessage = (char *) malloc(nMessageLen);
+ snprintf( pszMessage, nMessageLen, "Unable to open %s.shx or %s.SHX."
+ "Try --config SHAPE_RESTORE_SHX true to restore or create it",
pszBasename, pszBasename );
psHooks->Error( pszMessage );
free( pszMessage );
free( pszBasename );
/* -------------------------------------------------------------------- */
-/* Read the file size from the SHP file. */
+/* Read the file size from the SHP file. */
/* -------------------------------------------------------------------- */
pabyBuf = (uchar *) malloc(100);
psSHP->sHooks.FRead( pabyBuf, 100, 1, psSHP->fpSHP );
- psSHP->nFileSize = ((unsigned int)pabyBuf[24] * 256 * 256 * 256
- + (unsigned int)pabyBuf[25] * 256 * 256
- + (unsigned int)pabyBuf[26] * 256
- + (unsigned int)pabyBuf[27]) * 2;
+ psSHP->nFileSize = ((unsigned int)pabyBuf[24]<<24)|(pabyBuf[25]<<16)|
+ (pabyBuf[26]<<8)|pabyBuf[27];
+ if( psSHP->nFileSize < UINT_MAX / 2 )
+ psSHP->nFileSize *= 2;
+ else
+ psSHP->nFileSize = (UINT_MAX / 2) * 2;
/* -------------------------------------------------------------------- */
/* Read SHX file Header info */
/* -------------------------------------------------------------------- */
- if( psSHP->sHooks.FRead( pabyBuf, 100, 1, psSHP->fpSHX ) != 1
- || pabyBuf[0] != 0
- || pabyBuf[1] != 0
- || pabyBuf[2] != 0x27
+ if( psSHP->sHooks.FRead( pabyBuf, 100, 1, psSHP->fpSHX ) != 1
+ || pabyBuf[0] != 0
+ || pabyBuf[1] != 0
+ || pabyBuf[2] != 0x27
|| (pabyBuf[3] != 0x0a && pabyBuf[3] != 0x0d) )
{
psSHP->sHooks.Error( ".shx file is unreadable, or corrupt." );
psSHP->sHooks.FClose( psSHP->fpSHP );
psSHP->sHooks.FClose( psSHP->fpSHX );
+ free( pabyBuf );
free( psSHP );
return( NULL );
}
- psSHP->nRecords = pabyBuf[27] + pabyBuf[26] * 256
- + pabyBuf[25] * 256 * 256 + pabyBuf[24] * 256 * 256 * 256;
- psSHP->nRecords = (psSHP->nRecords*2 - 100) / 8;
+ psSHP->nRecords = pabyBuf[27]|(pabyBuf[26]<<8)|(pabyBuf[25]<<16)|
+ ((pabyBuf[24] & 0x7F)<<24);
+ psSHP->nRecords = (psSHP->nRecords - 50) / 4;
psSHP->nShapeType = pabyBuf[32];
if( psSHP->nRecords < 0 || psSHP->nRecords > 256000000 )
{
- char szError[200];
-
- sprintf( szError,
+ char szErrorMsg[200];
+
+ snprintf( szErrorMsg, sizeof(szErrorMsg),
"Record count in .shp header is %d, which seems\n"
"unreasonable. Assuming header is corrupt.",
psSHP->nRecords );
- psSHP->sHooks.Error( szError );
+ szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
+ psSHP->sHooks.Error( szErrorMsg );
psSHP->sHooks.FClose( psSHP->fpSHP );
psSHP->sHooks.FClose( psSHP->fpSHX );
free( psSHP );
return( NULL );
}
+ /* If a lot of records are advertized, check that the file is big enough */
+ /* to hold them */
+ if( psSHP->nRecords >= 1024 * 1024 )
+ {
+ SAOffset nFileSize;
+ psSHP->sHooks.FSeek( psSHP->fpSHX, 0, 2 );
+ nFileSize = psSHP->sHooks.FTell( psSHP->fpSHX );
+ if( nFileSize > 100 &&
+ nFileSize/2 < (SAOffset)(psSHP->nRecords * 4 + 50) )
+ {
+ psSHP->nRecords = (int)((nFileSize - 100) / 8);
+ }
+ psSHP->sHooks.FSeek( psSHP->fpSHX, 100, 0 );
+ }
+
/* -------------------------------------------------------------------- */
/* Read the bounds. */
/* -------------------------------------------------------------------- */
memcpy( &dValue, pabyBuf+60, 8 );
psSHP->adBoundsMax[1] = dValue;
- if( bBigEndian ) SwapWord( 8, pabyBuf+68 ); /* z */
+ if( bBigEndian ) SwapWord( 8, pabyBuf+68 ); /* z */
memcpy( &dValue, pabyBuf+68, 8 );
psSHP->adBoundsMin[2] = dValue;
-
+
if( bBigEndian ) SwapWord( 8, pabyBuf+76 );
memcpy( &dValue, pabyBuf+76, 8 );
psSHP->adBoundsMax[2] = dValue;
-
- if( bBigEndian ) SwapWord( 8, pabyBuf+84 ); /* z */
+
+ if( bBigEndian ) SwapWord( 8, pabyBuf+84 ); /* z */
memcpy( &dValue, pabyBuf+84, 8 );
psSHP->adBoundsMin[3] = dValue;
free( pabyBuf );
/* -------------------------------------------------------------------- */
-/* Read the .shx file to get the offsets to each record in */
-/* the .shp file. */
+/* Read the .shx file to get the offsets to each record in */
+/* the .shp file. */
/* -------------------------------------------------------------------- */
psSHP->nMaxRecords = psSHP->nRecords;
malloc(sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) );
psSHP->panRecSize = (unsigned int *)
malloc(sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) );
- pabyBuf = (uchar *) malloc(8 * MAX(1,psSHP->nRecords) );
+ if( bLazySHXLoading )
+ pabyBuf = NULL;
+ else
+ pabyBuf = (uchar *) malloc(8 * MAX(1,psSHP->nRecords) );
if (psSHP->panRecOffset == NULL ||
psSHP->panRecSize == NULL ||
- pabyBuf == NULL)
+ (!bLazySHXLoading && pabyBuf == NULL))
{
- char szError[200];
+ char szErrorMsg[200];
- sprintf(szError,
+ snprintf( szErrorMsg, sizeof(szErrorMsg),
"Not enough memory to allocate requested memory (nRecords=%d).\n"
- "Probably broken SHP file",
+ "Probably broken SHP file",
psSHP->nRecords );
- psSHP->sHooks.Error( szError );
+ szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
+ psSHP->sHooks.Error( szErrorMsg );
psSHP->sHooks.FClose( psSHP->fpSHP );
psSHP->sHooks.FClose( psSHP->fpSHX );
if (psSHP->panRecOffset) free( psSHP->panRecOffset );
return( NULL );
}
- if( (int) psSHP->sHooks.FRead( pabyBuf, 8, psSHP->nRecords, psSHP->fpSHX )
+ if( bLazySHXLoading )
+ {
+ memset(psSHP->panRecOffset, 0, sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) );
+ memset(psSHP->panRecSize, 0, sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) );
+ return( psSHP );
+ }
+
+ if( (int) psSHP->sHooks.FRead( pabyBuf, 8, psSHP->nRecords, psSHP->fpSHX )
!= psSHP->nRecords )
{
- char szError[200];
+ char szErrorMsg[200];
- sprintf( szError,
- "Failed to read all values for %d records in .shx file.",
- psSHP->nRecords );
- psSHP->sHooks.Error( szError );
+ snprintf( szErrorMsg, sizeof(szErrorMsg),
+ "Failed to read all values for %d records in .shx file: %s.",
+ psSHP->nRecords, strerror(errno) );
+ szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
+ psSHP->sHooks.Error( szErrorMsg );
/* SHX is short or unreadable for some reason. */
psSHP->sHooks.FClose( psSHP->fpSHP );
return( NULL );
}
-
+
/* In read-only mode, we can close the SHX now */
if (strcmp(pszAccess, "rb") == 0)
{
for( i = 0; i < psSHP->nRecords; i++ )
{
- int32 nOffset, nLength;
+ unsigned int nOffset, nLength;
memcpy( &nOffset, pabyBuf + i * 8, 4 );
if( !bBigEndian ) SwapWord( 4, &nOffset );
memcpy( &nLength, pabyBuf + i * 8 + 4, 4 );
if( !bBigEndian ) SwapWord( 4, &nLength );
+ if( nOffset > (unsigned int)INT_MAX )
+ {
+ char str[128];
+ snprintf( str, sizeof(str),
+ "Invalid offset for entity %d", i);
+ str[sizeof(str)-1] = '\0';
+
+ psSHP->sHooks.Error( str );
+ SHPClose(psSHP);
+ free( pabyBuf );
+ return NULL;
+ }
+ if( nLength > (unsigned int)(INT_MAX / 2 - 4) )
+ {
+ char str[128];
+ snprintf( str, sizeof(str),
+ "Invalid length for entity %d", i);
+ str[sizeof(str)-1] = '\0';
+
+ psSHP->sHooks.Error( str );
+ SHPClose(psSHP);
+ free( pabyBuf );
+ return NULL;
+ }
psSHP->panRecOffset[i] = nOffset*2;
psSHP->panRecSize[i] = nLength*2;
}
return( psSHP );
}
+/************************************************************************/
+/* SHPOpenLLEx() */
+/* */
+/* Open the .shp and .shx files based on the basename of the */
+/* files or either file name. It generally invokes SHPRestoreSHX() */
+/* in case when bRestoreSHX equals true. */
+/************************************************************************/
+
+SHPHandle SHPAPI_CALL
+SHPOpenLLEx( const char * pszLayer, const char * pszAccess, SAHooks *psHooks,
+ int bRestoreSHX )
+
+{
+ if ( !bRestoreSHX ) return SHPOpenLL ( pszLayer, pszAccess, psHooks );
+ else
+ {
+ if ( SHPRestoreSHX ( pszLayer, pszAccess, psHooks ) )
+ {
+ return SHPOpenLL ( pszLayer, pszAccess, psHooks );
+ }
+ }
+
+ return( NULL );
+}
+
+/************************************************************************/
+/* SHPRestoreSHX() */
+/* */
+/* Restore .SHX file using associated .SHP file. */
+/* */
+/************************************************************************/
+
+int SHPAPI_CALL
+SHPRestoreSHX ( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
+
+{
+ char *pszFullname, *pszBasename;
+ SAFile fpSHP, fpSHX;
+
+
+ uchar *pabyBuf;
+ int i;
+ size_t nFullnameLen;
+ unsigned int nSHPFilesize;
+
+ size_t nMessageLen;
+ char *pszMessage;
+
+ unsigned int nCurrentRecordOffset = 0;
+ unsigned int nCurrentSHPOffset = 100;
+ size_t nRealSHXContentSize = 100;
+
+ const char pszSHXAccess[] = "w+b";
+ char *pabySHXHeader;
+ char abyReadedRecord[8];
+ unsigned int niRecord = 0;
+ unsigned int nRecordLength = 0;
+ unsigned int nRecordOffset = 50;
+
+/* -------------------------------------------------------------------- */
+/* Ensure the access string is one of the legal ones. We */
+/* ensure the result string indicates binary to avoid common */
+/* problems on Windows. */
+/* -------------------------------------------------------------------- */
+ if( strcmp(pszAccess,"rb+") == 0 || strcmp(pszAccess,"r+b") == 0
+ || strcmp(pszAccess,"r+") == 0 )
+ pszAccess = "r+b";
+ else
+ {
+ pszAccess = "rb";
+ }
+
+/* -------------------------------------------------------------------- */
+/* Establish the byte order on this machine. */
+/* -------------------------------------------------------------------- */
+#if !defined(bBigEndian)
+ i = 1;
+ if( *((uchar *) &i) == 1 )
+ bBigEndian = FALSE;
+ else
+ bBigEndian = TRUE;
+#endif
+
+/* -------------------------------------------------------------------- */
+/* Compute the base (layer) name. If there is any extension */
+/* on the passed in filename we will strip it off. */
+/* -------------------------------------------------------------------- */
+ pszBasename = (char *) malloc(strlen(pszLayer)+5);
+ strcpy( pszBasename, pszLayer );
+ for( i = (int)strlen(pszBasename)-1;
+ i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
+ && pszBasename[i] != '\\';
+ i-- ) {}
+
+ if( pszBasename[i] == '.' )
+ pszBasename[i] = '\0';
+
+/* -------------------------------------------------------------------- */
+/* Open the .shp file. Note that files pulled from */
+/* a PC to Unix with upper case filenames won't work! */
+/* -------------------------------------------------------------------- */
+ nFullnameLen = strlen(pszBasename) + 5;
+ pszFullname = (char *) malloc(nFullnameLen);
+ snprintf( pszFullname, nFullnameLen, "%s.shp", pszBasename ) ;
+ fpSHP = psHooks->FOpen(pszFullname, pszAccess );
+ if( fpSHP == NULL )
+ {
+ snprintf( pszFullname, nFullnameLen, "%s.SHP", pszBasename );
+ fpSHP = psHooks->FOpen(pszFullname, pszAccess );
+ }
+
+ if( fpSHP == NULL )
+ {
+ nMessageLen = strlen(pszBasename)*2+256;
+ pszMessage = (char *) malloc(nMessageLen);
+ snprintf( pszMessage, nMessageLen, "Unable to open %s.shp or %s.SHP.",
+ pszBasename, pszBasename );
+ psHooks->Error( pszMessage );
+ free( pszMessage );
+
+ free( pszBasename );
+ free( pszFullname );
+
+ return( 0 );
+ }
+
+/* -------------------------------------------------------------------- */
+/* Read the file size from the SHP file. */
+/* -------------------------------------------------------------------- */
+ pabyBuf = (uchar *) malloc(100);
+ psHooks->FRead( pabyBuf, 100, 1, fpSHP );
+
+ nSHPFilesize = ((unsigned int)pabyBuf[24]<<24)|(pabyBuf[25]<<16)|
+ (pabyBuf[26]<<8)|pabyBuf[27];
+ if( nSHPFilesize < UINT_MAX / 2 )
+ nSHPFilesize *= 2;
+ else
+ nSHPFilesize = (UINT_MAX / 2) * 2;
+
+ snprintf( pszFullname, nFullnameLen, "%s.shx", pszBasename );
+ fpSHX = psHooks->FOpen( pszFullname, pszSHXAccess );
+
+ if( fpSHX == NULL )
+ {
+ nMessageLen = strlen( pszBasename ) * 2 + 256;
+ pszMessage = (char *) malloc( nMessageLen );
+ snprintf( pszMessage, nMessageLen, "Error opening file %s.shx for writing",
+ pszBasename );
+ psHooks->Error( pszMessage );
+ free( pszMessage );
+
+ psHooks->FClose( fpSHX );
+
+ free( pabyBuf );
+ free( pszBasename );
+ free( pszFullname );
+
+ return( 0 );
+ }
+
+/* -------------------------------------------------------------------- */
+/* Open SHX and create it using SHP file content. */
+/* -------------------------------------------------------------------- */
+ psHooks->FSeek( fpSHP, 100, 0 );
+ pabySHXHeader = (char *) malloc ( 100 );
+ memcpy( pabySHXHeader, pabyBuf, 100 );
+ psHooks->FWrite( pabySHXHeader, 100, 1, fpSHX );
+
+ while( nCurrentSHPOffset < nSHPFilesize )
+ {
+ if( psHooks->FRead( &niRecord, 4, 1, fpSHP ) == 1 &&
+ psHooks->FRead( &nRecordLength, 4, 1, fpSHP ) == 1)
+ {
+ if( !bBigEndian ) SwapWord( 4, &nRecordOffset );
+ memcpy( abyReadedRecord, &nRecordOffset, 4 );
+ memcpy( abyReadedRecord + 4, &nRecordLength, 4 );
+
+ psHooks->FWrite( abyReadedRecord, 8, 1, fpSHX );
+
+ if ( !bBigEndian ) SwapWord( 4, &nRecordOffset );
+ if ( !bBigEndian ) SwapWord( 4, &nRecordLength );
+ nRecordOffset += nRecordLength + 4;
+ nCurrentRecordOffset += 8;
+ nCurrentSHPOffset += 8 + nRecordLength * 2;
+
+ psHooks->FSeek( fpSHP, nCurrentSHPOffset, 0 );
+ nRealSHXContentSize += 8;
+ }
+ else
+ {
+ psHooks->Error( "Error parsing .shp to restore .shx" );
+
+ psHooks->FClose( fpSHX );
+ psHooks->FClose( fpSHP );
+
+ free( pabySHXHeader );
+ free( pszBasename );
+ free( pszFullname );
+
+ return( 0 );
+ }
+ }
+
+ nRealSHXContentSize /= 2; // Bytes counted -> WORDs
+ if( !bBigEndian ) SwapWord( 4, &nRealSHXContentSize );
+ psHooks->FSeek( fpSHX, 24, 0 );
+ psHooks->FWrite( &nRealSHXContentSize, 4, 1, fpSHX );
+
+ psHooks->FClose( fpSHP );
+ psHooks->FClose( fpSHX );
+
+ free ( pabyBuf );
+ free ( pszFullname );
+ free ( pszBasename );
+ free ( pabySHXHeader );
+
+ return( 1 );
+}
+
/************************************************************************/
/* SHPClose() */
/* */
{
free( psSHP->pabyRec );
}
-
+
+ if( psSHP->pabyObjectBuf != NULL )
+ {
+ free( psSHP->pabyObjectBuf );
+ }
+ if( psSHP->psCachedObject != NULL )
+ {
+ free( psSHP->psCachedObject );
+ }
+
free( psSHP );
}
+/************************************************************************/
+/* SHPSetFastModeReadObject() */
+/************************************************************************/
+
+/* If setting bFastMode = TRUE, the content of SHPReadObject() is owned by the SHPHandle. */
+/* So you cannot have 2 valid instances of SHPReadObject() simultaneously. */
+/* The SHPObject padfZ and padfM members may be NULL depending on the geometry */
+/* type. It is illegal to free at hand any of the pointer members of the SHPObject structure */
+void SHPAPI_CALL SHPSetFastModeReadObject( SHPHandle hSHP, int bFastMode )
+{
+ if( bFastMode )
+ {
+ if( hSHP->psCachedObject == NULL )
+ {
+ hSHP->psCachedObject = (SHPObject*) calloc(1, sizeof(SHPObject));
+ assert( hSHP->psCachedObject != NULL );
+ }
+ }
+
+ hSHP->bFastModeReadObject = bFastMode;
+}
+
/************************************************************************/
/* SHPGetInfo() */
/* */
if( psSHP == NULL )
return;
-
+
if( pnEntities != NULL )
*pnEntities = psSHP->nRecords;
uchar abyHeader[100];
int32 i32;
double dValue;
-
+ size_t nFullnameLen;
+
/* -------------------------------------------------------------------- */
/* Establish the byte order on this system. */
/* -------------------------------------------------------------------- */
+#if !defined(bBigEndian)
i = 1;
if( *((uchar *) &i) == 1 )
bBigEndian = FALSE;
else
bBigEndian = TRUE;
+#endif
/* -------------------------------------------------------------------- */
/* Compute the base (layer) name. If there is any extension */
/* -------------------------------------------------------------------- */
pszBasename = (char *) malloc(strlen(pszLayer)+5);
strcpy( pszBasename, pszLayer );
- for( i = strlen(pszBasename)-1;
+ for( i = (int)strlen(pszBasename)-1;
i > 0 && pszBasename[i] != '.' && pszBasename[i] != '/'
&& pszBasename[i] != '\\';
i-- ) {}
/* -------------------------------------------------------------------- */
/* Open the two files so we can write their headers. */
/* -------------------------------------------------------------------- */
- pszFullname = (char *) malloc(strlen(pszBasename) + 5);
- sprintf( pszFullname, "%s.shp", pszBasename );
+ nFullnameLen = strlen(pszBasename) + 5;
+ pszFullname = (char *) malloc(nFullnameLen);
+ snprintf( pszFullname, nFullnameLen, "%s.shp", pszBasename );
fpSHP = psHooks->FOpen(pszFullname, "wb" );
if( fpSHP == NULL )
{
- psHooks->Error( "Failed to create file .shp file." );
+ char szErrorMsg[200];
+ snprintf( szErrorMsg, sizeof(szErrorMsg),
+ "Failed to create file %s: %s",
+ pszFullname, strerror(errno) );
+ psHooks->Error( szErrorMsg );
+
goto error;
}
- sprintf( pszFullname, "%s.shx", pszBasename );
+ snprintf( pszFullname, nFullnameLen, "%s.shx", pszBasename );
fpSHX = psHooks->FOpen(pszFullname, "wb" );
if( fpSHX == NULL )
{
- psHooks->Error( "Failed to create file .shx file." );
+ char szErrorMsg[200];
+ snprintf( szErrorMsg, sizeof(szErrorMsg),
+ "Failed to create file %s: %s",
+ pszFullname, strerror(errno) );
+ psHooks->Error( szErrorMsg );
goto error;
}
/* -------------------------------------------------------------------- */
/* Prepare header block for .shp file. */
/* -------------------------------------------------------------------- */
- for( i = 0; i < 100; i++ )
- abyHeader[i] = 0;
+ memset( abyHeader, 0, sizeof(abyHeader) );
abyHeader[2] = 0x27; /* magic cookie */
abyHeader[3] = 0x0a;
i32 = 50; /* file size */
ByteCopy( &i32, abyHeader+24, 4 );
if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
-
+
i32 = 1000; /* version */
ByteCopy( &i32, abyHeader+28, 4 );
if( bBigEndian ) SwapWord( 4, abyHeader+28 );
-
+
i32 = nShapeType; /* shape type */
ByteCopy( &i32, abyHeader+32, 4 );
if( bBigEndian ) SwapWord( 4, abyHeader+32 );
/* -------------------------------------------------------------------- */
if( psHooks->FWrite( abyHeader, 100, 1, fpSHP ) != 1 )
{
- psHooks->Error( "Failed to write .shp header." );
+ char szErrorMsg[200];
+
+ snprintf( szErrorMsg, sizeof(szErrorMsg),
+ "Failed to write .shp header: %s", strerror(errno) );
+ szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
+ psHooks->Error( szErrorMsg );
+
goto error;
}
i32 = 50; /* file size */
ByteCopy( &i32, abyHeader+24, 4 );
if( !bBigEndian ) SwapWord( 4, abyHeader+24 );
-
+
if( psHooks->FWrite( abyHeader, 100, 1, fpSHX ) != 1 )
{
- psHooks->Error( "Failed to write .shx header." );
+ char szErrorMsg[200];
+
+ snprintf( szErrorMsg, sizeof(szErrorMsg),
+ "Failure writing .shx header: %s", strerror(errno) );
+ szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
+ psHooks->Error( szErrorMsg );
+
goto error;
}
{
int i;
-
+
/* -------------------------------------------------------------------- */
/* Build extents for this object. */
/* -------------------------------------------------------------------- */
psObject->dfZMin = psObject->dfZMax = psObject->padfZ[0];
psObject->dfMMin = psObject->dfMMax = psObject->padfM[0];
}
-
+
for( i = 0; i < psObject->nVertices; i++ )
{
psObject->dfXMin = MIN(psObject->dfXMin, psObject->padfX[i]);
psObject->panPartStart[0] = 0;
psObject->panPartType[0] = SHPP_RING;
-
+
for( i = 0; i < nParts; i++ )
{
- if( psObject->panPartStart != NULL )
+ if( panPartStart != NULL )
psObject->panPartStart[i] = panPartStart[i];
if( panPartType != NULL )
/* -------------------------------------------------------------------- */
if( nVertices > 0 )
{
- psObject->padfX = (double *) calloc(sizeof(double),nVertices);
- psObject->padfY = (double *) calloc(sizeof(double),nVertices);
- psObject->padfZ = (double *) calloc(sizeof(double),nVertices);
- psObject->padfM = (double *) calloc(sizeof(double),nVertices);
-
- for( i = 0; i < nVertices; i++ )
- {
- if( padfX != NULL )
- psObject->padfX[i] = padfX[i];
- if( padfY != NULL )
- psObject->padfY[i] = padfY[i];
- if( padfZ != NULL && bHasZ )
- psObject->padfZ[i] = padfZ[i];
- if( padfM != NULL && bHasM )
- psObject->padfM[i] = padfM[i];
- }
+ size_t nSize = sizeof(double) * nVertices;
+ psObject->padfX = (double *) padfX ? malloc(nSize) :
+ calloc(sizeof(double),nVertices);
+ psObject->padfY = (double *) padfY ? malloc(nSize) :
+ calloc(sizeof(double),nVertices);
+ psObject->padfZ = (double *) padfZ && bHasZ ? malloc(nSize) :
+ calloc(sizeof(double),nVertices);
+ psObject->padfM = (double *) padfM && bHasM ? malloc(nSize) :
+ calloc(sizeof(double),nVertices);
+ if( padfX != NULL )
+ memcpy(psObject->padfX, padfX, nSize);
+ if( padfY != NULL )
+ memcpy(psObject->padfY, padfY, nSize);
+ if( padfZ != NULL && bHasZ )
+ memcpy(psObject->padfZ, padfZ, nSize);
if( padfM != NULL && bHasM )
+ {
+ memcpy(psObject->padfM, padfM, nSize);
psObject->bMeasureIsUsed = TRUE;
+ }
}
/* -------------------------------------------------------------------- */
return( SHPCreateObject( nSHPType, -1, 0, NULL, NULL,
nVertices, padfX, padfY, padfZ, NULL ) );
}
-
+
/************************************************************************/
/* SHPWriteObject() */
/* */
int SHPAPI_CALL
SHPWriteObject(SHPHandle psSHP, int nShapeId, SHPObject * psObject )
-
+
{
unsigned int nRecordOffset, nRecordSize=0;
int i;
uchar *pabyRec;
int32 i32;
+ int bAppendToLastRecord = FALSE;
+ int bAppendToFile = FALSE;
psSHP->bUpdated = TRUE;
/* Ensure that shape object matches the type of the file it is */
/* being written to. */
/* -------------------------------------------------------------------- */
- assert( psObject->nSHPType == psSHP->nShapeType
+ assert( psObject->nSHPType == psSHP->nShapeType
|| psObject->nSHPType == SHPT_NULL );
/* -------------------------------------------------------------------- */
/* assertion, or if they are disabled, set the shapeid to -1 */
/* for appends. */
/* -------------------------------------------------------------------- */
- assert( nShapeId == -1
+ assert( nShapeId == -1
|| (nShapeId >= 0 && nShapeId < psSHP->nRecords) );
if( nShapeId != -1 && nShapeId >= psSHP->nRecords )
/* -------------------------------------------------------------------- */
if( nShapeId == -1 && psSHP->nRecords+1 > psSHP->nMaxRecords )
{
- psSHP->nMaxRecords =(int) ( psSHP->nMaxRecords * 1.3 + 100);
+ int nNewMaxRecords = psSHP->nMaxRecords + psSHP->nMaxRecords / 3 + 100;
+ unsigned int* panRecOffsetNew;
+ unsigned int* panRecSizeNew;
+
+ panRecOffsetNew = (unsigned int *)
+ SfRealloc(psSHP->panRecOffset,sizeof(unsigned int) * nNewMaxRecords );
+ if( panRecOffsetNew == NULL )
+ return -1;
+ psSHP->panRecOffset = panRecOffsetNew;
+
+ panRecSizeNew = (unsigned int *)
+ SfRealloc(psSHP->panRecSize,sizeof(unsigned int) * nNewMaxRecords );
+ if( panRecSizeNew == NULL )
+ return -1;
+ psSHP->panRecSize = panRecSizeNew;
- psSHP->panRecOffset = (unsigned int *)
- SfRealloc(psSHP->panRecOffset,sizeof(unsigned int) * psSHP->nMaxRecords );
- psSHP->panRecSize = (unsigned int *)
- SfRealloc(psSHP->panRecSize,sizeof(unsigned int) * psSHP->nMaxRecords );
+ psSHP->nMaxRecords = nNewMaxRecords;
}
/* -------------------------------------------------------------------- */
/* Initialize record. */
/* -------------------------------------------------------------------- */
- pabyRec = (uchar *) malloc(psObject->nVertices * 4 * sizeof(double)
+ pabyRec = (uchar *) malloc(psObject->nVertices * 4 * sizeof(double)
+ psObject->nParts * 8 + 128);
-
+ if( pabyRec == NULL )
+ return -1;
+
/* -------------------------------------------------------------------- */
/* Extract vertices for a Polygon or Arc. */
/* -------------------------------------------------------------------- */
if( psObject->nSHPType == SHPT_POLYGON
|| psObject->nSHPType == SHPT_POLYGONZ
|| psObject->nSHPType == SHPT_POLYGONM
- || psObject->nSHPType == SHPT_ARC
+ || psObject->nSHPType == SHPT_ARC
|| psObject->nSHPType == SHPT_ARCZ
|| psObject->nSHPType == SHPT_ARCM
|| psObject->nSHPType == SHPT_MULTIPATCH )
{
int32 nPoints, nParts;
- int i;
nPoints = psObject->nVertices;
nParts = psObject->nParts;
if( bBigEndian )
SwapWord( 8, pabyRec + nRecordSize );
-
+
if( bBigEndian )
SwapWord( 8, pabyRec + nRecordSize + 8 );
ByteCopy( &(psObject->dfZMin), pabyRec + nRecordSize, 8 );
if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
nRecordSize += 8;
-
+
ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 );
if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
nRecordSize += 8;
if( psObject->bMeasureIsUsed
&& (psObject->nSHPType == SHPT_POLYGONM
|| psObject->nSHPType == SHPT_ARCM
-#ifndef DISABLE_MULTIPATCH_MEASURE
+#ifndef DISABLE_MULTIPATCH_MEASURE
|| psObject->nSHPType == SHPT_MULTIPATCH
-#endif
+#endif
|| psObject->nSHPType == SHPT_POLYGONZ
|| psObject->nSHPType == SHPT_ARCZ) )
{
ByteCopy( &(psObject->dfMMin), pabyRec + nRecordSize, 8 );
if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
nRecordSize += 8;
-
+
ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 );
if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
nRecordSize += 8;
|| psObject->nSHPType == SHPT_MULTIPOINTM )
{
int32 nPoints;
- int i;
nPoints = psObject->nVertices;
if( bBigEndian ) SwapWord( 4, &nPoints );
ByteCopy( &nPoints, pabyRec + 44, 4 );
-
+
for( i = 0; i < psObject->nVertices; i++ )
{
ByteCopy( psObject->padfX + i, pabyRec + 48 + i*16, 8 );
ByteCopy( &(psObject->dfZMax), pabyRec + nRecordSize, 8 );
if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
nRecordSize += 8;
-
+
for( i = 0; i < psObject->nVertices; i++ )
{
ByteCopy( psObject->padfZ + i, pabyRec + nRecordSize, 8 );
ByteCopy( &(psObject->dfMMax), pabyRec + nRecordSize, 8 );
if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
nRecordSize += 8;
-
+
for( i = 0; i < psObject->nVertices; i++ )
{
ByteCopy( psObject->padfM + i, pabyRec + nRecordSize, 8 );
if( bBigEndian ) SwapWord( 8, pabyRec + 20 );
nRecordSize = 28;
-
+
if( psObject->nSHPType == SHPT_POINTZ )
{
ByteCopy( psObject->padfZ, pabyRec + nRecordSize, 8 );
if( bBigEndian ) SwapWord( 8, pabyRec + nRecordSize );
nRecordSize += 8;
}
-
+
if( psObject->bMeasureIsUsed
&& (psObject->nSHPType == SHPT_POINTZ
|| psObject->nSHPType == SHPT_POINTM) )
/* -------------------------------------------------------------------- */
/* Establish where we are going to put this record. If we are */
-/* rewriting and existing record, and it will fit, then put it */
-/* back where the original came from. Otherwise write at the end. */
+/* rewriting the last record of the file, then we can update it in */
+/* place. Otherwise if rewriting an existing record, and it will */
+/* fit, then put it back where the original came from. Otherwise */
+/* write at the end. */
/* -------------------------------------------------------------------- */
- if( nShapeId == -1 || psSHP->panRecSize[nShapeId] < nRecordSize-8 )
+ if( nShapeId != -1 && psSHP->panRecOffset[nShapeId] +
+ psSHP->panRecSize[nShapeId] + 8 == psSHP->nFileSize )
+ {
+ nRecordOffset = psSHP->panRecOffset[nShapeId];
+ bAppendToLastRecord = TRUE;
+ }
+ else if( nShapeId == -1 || psSHP->panRecSize[nShapeId] < nRecordSize-8 )
{
- unsigned int nExpectedSize = psSHP->nFileSize + nRecordSize;
- if( nExpectedSize < psSHP->nFileSize ) // due to unsigned int overflow
+ if( psSHP->nFileSize > UINT_MAX - nRecordSize)
{
char str[128];
- sprintf( str, "Failed to write shape object. "
+ snprintf( str, sizeof(str), "Failed to write shape object. "
"File size cannot reach %u + %u.",
psSHP->nFileSize, nRecordSize );
+ str[sizeof(str)-1] = '\0';
psSHP->sHooks.Error( str );
free( pabyRec );
return -1;
}
- if( nShapeId == -1 )
- nShapeId = psSHP->nRecords++;
-
- psSHP->panRecOffset[nShapeId] = nRecordOffset = psSHP->nFileSize;
- psSHP->panRecSize[nShapeId] = nRecordSize-8;
- psSHP->nFileSize += nRecordSize;
+ bAppendToFile = TRUE;
+ nRecordOffset = psSHP->nFileSize;
}
else
{
nRecordOffset = psSHP->panRecOffset[nShapeId];
- psSHP->panRecSize[nShapeId] = nRecordSize-8;
}
-
+
/* -------------------------------------------------------------------- */
/* Set the shape type, record number, and record size. */
/* -------------------------------------------------------------------- */
- i32 = nShapeId+1; /* record # */
+ i32 = (nShapeId < 0) ? psSHP->nRecords+1 : nShapeId+1; /* record # */
if( !bBigEndian ) SwapWord( 4, &i32 );
ByteCopy( &i32, pabyRec, 4 );
/* -------------------------------------------------------------------- */
if( psSHP->sHooks.FSeek( psSHP->fpSHP, nRecordOffset, 0 ) != 0 )
{
- psSHP->sHooks.Error( "Error in psSHP->sHooks.FSeek() while writing object to .shp file." );
+ char szErrorMsg[200];
+
+ snprintf( szErrorMsg, sizeof(szErrorMsg),
+ "Error in psSHP->sHooks.FSeek() while writing object to .shp file: %s",
+ strerror(errno) );
+ szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
+ psSHP->sHooks.Error( szErrorMsg );
+
free( pabyRec );
return -1;
}
if( psSHP->sHooks.FWrite( pabyRec, nRecordSize, 1, psSHP->fpSHP ) < 1 )
{
- psSHP->sHooks.Error( "Error in psSHP->sHooks.Fwrite() while writing object to .shp file." );
+ char szErrorMsg[200];
+
+ snprintf( szErrorMsg, sizeof(szErrorMsg),
+ "Error in psSHP->sHooks.FWrite() while writing object of %u bytes to .shp file: %s",
+ nRecordSize, strerror(errno) );
+ szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
+ psSHP->sHooks.Error( szErrorMsg );
+
free( pabyRec );
return -1;
}
-
+
free( pabyRec );
+ if( bAppendToLastRecord )
+ {
+ psSHP->nFileSize = psSHP->panRecOffset[nShapeId] + nRecordSize;
+ }
+ else if( bAppendToFile )
+ {
+ if( nShapeId == -1 )
+ nShapeId = psSHP->nRecords++;
+
+ psSHP->panRecOffset[nShapeId] = psSHP->nFileSize;
+ psSHP->nFileSize += nRecordSize;
+ }
+ psSHP->panRecSize[nShapeId] = nRecordSize-8;
+
/* -------------------------------------------------------------------- */
/* Expand file wide bounds based on this shape. */
/* -------------------------------------------------------------------- */
{
psSHP->adBoundsMin[0] = psSHP->adBoundsMax[0] = psObject->padfX[0];
psSHP->adBoundsMin[1] = psSHP->adBoundsMax[1] = psObject->padfY[0];
- psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = psObject->padfZ[0];
- psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = psObject->padfM[0];
+ psSHP->adBoundsMin[2] = psSHP->adBoundsMax[2] = psObject->padfZ ? psObject->padfZ[0] : 0.0;
+ psSHP->adBoundsMin[3] = psSHP->adBoundsMax[3] = psObject->padfM ? psObject->padfM[0] : 0.0;
}
}
{
psSHP->adBoundsMin[0] = MIN(psSHP->adBoundsMin[0],psObject->padfX[i]);
psSHP->adBoundsMin[1] = MIN(psSHP->adBoundsMin[1],psObject->padfY[i]);
- psSHP->adBoundsMin[2] = MIN(psSHP->adBoundsMin[2],psObject->padfZ[i]);
- psSHP->adBoundsMin[3] = MIN(psSHP->adBoundsMin[3],psObject->padfM[i]);
psSHP->adBoundsMax[0] = MAX(psSHP->adBoundsMax[0],psObject->padfX[i]);
psSHP->adBoundsMax[1] = MAX(psSHP->adBoundsMax[1],psObject->padfY[i]);
- psSHP->adBoundsMax[2] = MAX(psSHP->adBoundsMax[2],psObject->padfZ[i]);
- psSHP->adBoundsMax[3] = MAX(psSHP->adBoundsMax[3],psObject->padfM[i]);
+ if( psObject->padfZ )
+ {
+ psSHP->adBoundsMin[2] = MIN(psSHP->adBoundsMin[2],psObject->padfZ[i]);
+ psSHP->adBoundsMax[2] = MAX(psSHP->adBoundsMax[2],psObject->padfZ[i]);
+ }
+ if( psObject->padfM )
+ {
+ psSHP->adBoundsMin[3] = MIN(psSHP->adBoundsMin[3],psObject->padfM[i]);
+ psSHP->adBoundsMax[3] = MAX(psSHP->adBoundsMax[3],psObject->padfM[i]);
+ }
}
return( nShapeId );
}
+/************************************************************************/
+/* SHPAllocBuffer() */
+/************************************************************************/
+
+static void* SHPAllocBuffer(unsigned char** pBuffer, int nSize)
+{
+ unsigned char* pRet;
+
+ if( pBuffer == NULL )
+ return calloc(1, nSize);
+
+ pRet = *pBuffer;
+ if( pRet == NULL )
+ return NULL;
+
+ (*pBuffer) += nSize;
+ return pRet;
+}
+
+/************************************************************************/
+/* SHPReallocObjectBufIfNecessary() */
+/************************************************************************/
+
+static unsigned char* SHPReallocObjectBufIfNecessary ( SHPHandle psSHP,
+ int nObjectBufSize )
+{
+ unsigned char* pBuffer;
+ if( nObjectBufSize == 0 )
+ {
+ nObjectBufSize = 4 * sizeof(double);
+ }
+ if( nObjectBufSize > psSHP->nObjectBufSize )
+ {
+ pBuffer = (unsigned char*) realloc( psSHP->pabyObjectBuf, nObjectBufSize );
+ if( pBuffer != NULL )
+ {
+ psSHP->pabyObjectBuf = pBuffer;
+ psSHP->nObjectBufSize = nObjectBufSize;
+ }
+ }
+ else
+ pBuffer = psSHP->pabyObjectBuf;
+ return pBuffer;
+}
+
/************************************************************************/
/* SHPReadObject() */
/* */
int nEntitySize, nRequiredSize;
SHPObject *psShape;
char szErrorMsg[128];
+ int nSHPType;
+ int nBytesRead;
/* -------------------------------------------------------------------- */
/* Validate the record/entity number. */
if( hEntity < 0 || hEntity >= psSHP->nRecords )
return( NULL );
+/* -------------------------------------------------------------------- */
+/* Read offset/length from SHX loading if necessary. */
+/* -------------------------------------------------------------------- */
+ if( psSHP->panRecOffset[hEntity] == 0 && psSHP->fpSHX != NULL )
+ {
+ unsigned int nOffset, nLength;
+
+ if( psSHP->sHooks.FSeek( psSHP->fpSHX, 100 + 8 * hEntity, 0 ) != 0 ||
+ psSHP->sHooks.FRead( &nOffset, 1, 4, psSHP->fpSHX ) != 4 ||
+ psSHP->sHooks.FRead( &nLength, 1, 4, psSHP->fpSHX ) != 4 )
+ {
+ char str[128];
+ snprintf( str, sizeof(str),
+ "Error in fseek()/fread() reading object from .shx file at offset %d",
+ 100 + 8 * hEntity);
+ str[sizeof(str)-1] = '\0';
+
+ psSHP->sHooks.Error( str );
+ return NULL;
+ }
+ if( !bBigEndian ) SwapWord( 4, &nOffset );
+ if( !bBigEndian ) SwapWord( 4, &nLength );
+
+ if( nOffset > (unsigned int)INT_MAX )
+ {
+ char str[128];
+ snprintf( str, sizeof(str),
+ "Invalid offset for entity %d", hEntity);
+ str[sizeof(str)-1] = '\0';
+
+ psSHP->sHooks.Error( str );
+ return NULL;
+ }
+ if( nLength > (unsigned int)(INT_MAX / 2 - 4) )
+ {
+ char str[128];
+ snprintf( str, sizeof(str),
+ "Invalid length for entity %d", hEntity);
+ str[sizeof(str)-1] = '\0';
+
+ psSHP->sHooks.Error( str );
+ return NULL;
+ }
+
+ psSHP->panRecOffset[hEntity] = nOffset*2;
+ psSHP->panRecSize[hEntity] = nLength*2;
+ }
+
/* -------------------------------------------------------------------- */
/* Ensure our record buffer is large enough. */
/* -------------------------------------------------------------------- */
nEntitySize = psSHP->panRecSize[hEntity]+8;
if( nEntitySize > psSHP->nBufSize )
{
- psSHP->pabyRec = (uchar *) SfRealloc(psSHP->pabyRec,nEntitySize);
- if (psSHP->pabyRec == NULL)
+ uchar* pabyRecNew;
+ int nNewBufSize = nEntitySize;
+ if( nNewBufSize < INT_MAX - nNewBufSize / 3 )
+ nNewBufSize += nNewBufSize / 3;
+ else
+ nNewBufSize = INT_MAX;
+
+ /* Before allocating too much memory, check that the file is big enough */
+ /* and do not trust the file size in the header the first time we */
+ /* need to allocate more than 10 MB */
+ if( nNewBufSize >= 10 * 1024 * 1024 &&
+ psSHP->nBufSize < 10 * 1024 * 1024 )
{
- char szError[200];
+ SAOffset nFileSize;
+ psSHP->sHooks.FSeek( psSHP->fpSHP, 0, 2 );
+ nFileSize = psSHP->sHooks.FTell(psSHP->fpSHP);
+ if( nFileSize >= UINT_MAX )
+ psSHP->nFileSize = UINT_MAX;
+ else
+ psSHP->nFileSize = (unsigned int)nFileSize;
+ }
- /* Reallocate previous successfull size for following features */
- psSHP->pabyRec = (uchar *) malloc(psSHP->nBufSize);
+ if( psSHP->panRecOffset[hEntity] >= psSHP->nFileSize ||
+ /* We should normally use nEntitySize instead of*/
+ /* psSHP->panRecSize[hEntity] in the below test, but because of */
+ /* the case of non conformant .shx files detailed a bit below, */
+ /* let be more tolerant */
+ psSHP->panRecSize[hEntity] > psSHP->nFileSize - psSHP->panRecOffset[hEntity] )
+ {
+ char str[128];
+ snprintf( str, sizeof(str),
+ "Error in fread() reading object of size %d at offset %u from .shp file",
+ nEntitySize, psSHP->panRecOffset[hEntity] );
+ str[sizeof(str)-1] = '\0';
- sprintf( szError,
- "Not enough memory to allocate requested memory (nBufSize=%d). "
- "Probably broken SHP file", psSHP->nBufSize );
- psSHP->sHooks.Error( szError );
+ psSHP->sHooks.Error( str );
return NULL;
}
- /* Only set new buffer size after successfull alloc */
- psSHP->nBufSize = nEntitySize;
+ pabyRecNew = (uchar *) SfRealloc(psSHP->pabyRec,nNewBufSize);
+ if (pabyRecNew == NULL)
+ {
+ snprintf( szErrorMsg, sizeof(szErrorMsg),
+ "Not enough memory to allocate requested memory (nNewBufSize=%d). "
+ "Probably broken SHP file", nNewBufSize);
+ szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
+ psSHP->sHooks.Error( szErrorMsg );
+ return NULL;
+ }
+
+ /* Only set new buffer size after successful alloc */
+ psSHP->pabyRec = pabyRecNew;
+ psSHP->nBufSize = nNewBufSize;
}
/* In case we were not able to reallocate the buffer on a previous step */
* for example to detect if file is truncated.
*/
char str[128];
- sprintf( str,
+ snprintf( str, sizeof(str),
"Error in fseek() reading object from .shp file at offset %u",
psSHP->panRecOffset[hEntity]);
+ str[sizeof(str)-1] = '\0';
psSHP->sHooks.Error( str );
return NULL;
}
- if( psSHP->sHooks.FRead( psSHP->pabyRec, nEntitySize, 1, psSHP->fpSHP ) != 1 )
+ nBytesRead = (int)psSHP->sHooks.FRead( psSHP->pabyRec, 1, nEntitySize, psSHP->fpSHP );
+
+ /* Special case for a shapefile whose .shx content length field is not equal */
+ /* to the content length field of the .shp, which is a violation of "The */
+ /* content length stored in the index record is the same as the value stored in the main */
+ /* file record header." (http://www.esri.com/library/whitepapers/pdfs/shapefile.pdf, page 24) */
+ /* Actually in that case the .shx content length is equal to the .shp content length + */
+ /* 4 (16 bit words), representing the 8 bytes of the record header... */
+ if( nBytesRead >= 8 && nBytesRead == nEntitySize - 8 )
+ {
+ /* Do a sanity check */
+ int nSHPContentLength;
+ memcpy( &nSHPContentLength, psSHP->pabyRec + 4, 4 );
+ if( !bBigEndian ) SwapWord( 4, &(nSHPContentLength) );
+ if( nSHPContentLength < 0 ||
+ nSHPContentLength > INT_MAX / 2 - 4 ||
+ 2 * nSHPContentLength + 8 != nBytesRead )
+ {
+ char str[128];
+ snprintf( str, sizeof(str),
+ "Sanity check failed when trying to recover from inconsistent .shx/.shp with shape %d",
+ hEntity );
+ str[sizeof(str)-1] = '\0';
+
+ psSHP->sHooks.Error( str );
+ return NULL;
+ }
+ }
+ else if( nBytesRead != nEntitySize )
{
/*
* TODO - mloskot: Consider detailed diagnostics of shape file,
* for example to detect if file is truncated.
*/
char str[128];
- sprintf( str,
- "Error in fread() reading object of size %u at offset %u from .shp file",
+ snprintf( str, sizeof(str),
+ "Error in fread() reading object of size %d at offset %u from .shp file",
nEntitySize, psSHP->panRecOffset[hEntity] );
+ str[sizeof(str)-1] = '\0';
psSHP->sHooks.Error( str );
return NULL;
}
-/* -------------------------------------------------------------------- */
-/* Allocate and minimally initialize the object. */
-/* -------------------------------------------------------------------- */
- psShape = (SHPObject *) calloc(1,sizeof(SHPObject));
- psShape->nShapeId = hEntity;
- psShape->bMeasureIsUsed = FALSE;
-
if ( 8 + 4 > nEntitySize )
{
snprintf(szErrorMsg, sizeof(szErrorMsg),
"Corrupted .shp file : shape %d : nEntitySize = %d",
- hEntity, nEntitySize);
+ hEntity, nEntitySize);
+ szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
psSHP->sHooks.Error( szErrorMsg );
- SHPDestroyObject(psShape);
return NULL;
}
- memcpy( &psShape->nSHPType, psSHP->pabyRec + 8, 4 );
+ memcpy( &nSHPType, psSHP->pabyRec + 8, 4 );
- if( bBigEndian ) SwapWord( 4, &(psShape->nSHPType) );
+ if( bBigEndian ) SwapWord( 4, &(nSHPType) );
+
+/* -------------------------------------------------------------------- */
+/* Allocate and minimally initialize the object. */
+/* -------------------------------------------------------------------- */
+ if( psSHP->bFastModeReadObject )
+ {
+ if( psSHP->psCachedObject->bFastModeReadObject )
+ {
+ psSHP->sHooks.Error( "Invalid read pattern in fast read mode. "
+ "SHPDestroyObject() should be called." );
+ return NULL;
+ }
+
+ psShape = psSHP->psCachedObject;
+ memset(psShape, 0, sizeof(SHPObject));
+ }
+ else
+ psShape = (SHPObject *) calloc(1,sizeof(SHPObject));
+ psShape->nShapeId = hEntity;
+ psShape->nSHPType = nSHPType;
+ psShape->bMeasureIsUsed = FALSE;
+ psShape->bFastModeReadObject = psSHP->bFastModeReadObject;
/* ==================================================================== */
/* Extract vertices for a Polygon or Arc. */
|| psShape->nSHPType == SHPT_ARCM
|| psShape->nSHPType == SHPT_MULTIPATCH )
{
- int32_t nPoints, nParts;
+ int32 nPoints, nParts;
int i, nOffset;
+ unsigned char* pBuffer = NULL;
+ unsigned char** ppBuffer = NULL;
if ( 40 + 8 + 4 > nEntitySize )
{
snprintf(szErrorMsg, sizeof(szErrorMsg),
"Corrupted .shp file : shape %d : nEntitySize = %d",
- hEntity, nEntitySize);
+ hEntity, nEntitySize);
+ szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
psSHP->sHooks.Error( szErrorMsg );
SHPDestroyObject(psShape);
return NULL;
if( bBigEndian ) SwapWord( 4, &nPoints );
if( bBigEndian ) SwapWord( 4, &nParts );
- if (nPoints < 0 || nParts < 0 ||
+ /* nPoints and nParts are unsigned */
+ if (/* nPoints < 0 || nParts < 0 || */
nPoints > 50 * 1000 * 1000 || nParts > 10 * 1000 * 1000)
{
snprintf(szErrorMsg, sizeof(szErrorMsg),
- "Corrupted .shp file : shape %d, nPoints=%d, nParts=%d.",
+ "Corrupted .shp file : shape %d, nPoints=%u, nParts=%u.",
hEntity, nPoints, nParts);
+ szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
psSHP->sHooks.Error( szErrorMsg );
SHPDestroyObject(psShape);
return NULL;
}
-
+
/* With the previous checks on nPoints and nParts, */
/* we should not overflow here and after */
/* since 50 M * (16 + 8 + 8) = 1 600 MB */
if (nRequiredSize > nEntitySize)
{
snprintf(szErrorMsg, sizeof(szErrorMsg),
- "Corrupted .shp file : shape %d, nPoints=%d, nParts=%d, nEntitySize=%d.",
+ "Corrupted .shp file : shape %d, nPoints=%u, nParts=%u, nEntitySize=%d.",
hEntity, nPoints, nParts, nEntitySize);
+ szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
psSHP->sHooks.Error( szErrorMsg );
SHPDestroyObject(psShape);
return NULL;
}
+ if( psShape->bFastModeReadObject )
+ {
+ int nObjectBufSize = 4 * sizeof(double) * nPoints + 2 * sizeof(int) * nParts;
+ pBuffer = SHPReallocObjectBufIfNecessary(psSHP, nObjectBufSize);
+ ppBuffer = &pBuffer;
+ }
+
psShape->nVertices = nPoints;
- psShape->padfX = (double *) calloc(nPoints,sizeof(double));
- psShape->padfY = (double *) calloc(nPoints,sizeof(double));
- psShape->padfZ = (double *) calloc(nPoints,sizeof(double));
- psShape->padfM = (double *) calloc(nPoints,sizeof(double));
+ psShape->padfX = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
+ psShape->padfY = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
+ psShape->padfZ = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
+ psShape->padfM = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
psShape->nParts = nParts;
- psShape->panPartStart = (int *) calloc(nParts,sizeof(int));
- psShape->panPartType = (int *) calloc(nParts,sizeof(int));
-
+ psShape->panPartStart = (int *) SHPAllocBuffer(ppBuffer, nParts * sizeof(int));
+ psShape->panPartType = (int *) SHPAllocBuffer(ppBuffer, nParts * sizeof(int));
+
if (psShape->padfX == NULL ||
psShape->padfY == NULL ||
psShape->padfZ == NULL ||
psShape->panPartType == NULL)
{
snprintf(szErrorMsg, sizeof(szErrorMsg),
- "Not enough memory to allocate requested memory (nPoints=%d, nParts=%d) for shape %d. "
- "Probably broken SHP file", hEntity, nPoints, nParts );
+ "Not enough memory to allocate requested memory (nPoints=%u, nParts=%u) for shape %d. "
+ "Probably broken SHP file", nPoints, nParts, hEntity );
+ szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
psSHP->sHooks.Error( szErrorMsg );
SHPDestroyObject(psShape);
return NULL;
}
- for( i = 0; i < nParts; i++ )
+ for( i = 0; (int32)i < nParts; i++ )
psShape->panPartType[i] = SHPP_RING;
/* -------------------------------------------------------------------- */
/* Copy out the part array from the record. */
/* -------------------------------------------------------------------- */
memcpy( psShape->panPartStart, psSHP->pabyRec + 44 + 8, 4 * nParts );
- for( i = 0; i < nParts; i++ )
+ for( i = 0; (int32)i < nParts; i++ )
{
if( bBigEndian ) SwapWord( 4, psShape->panPartStart+i );
/* We check that the offset is inside the vertex array */
if (psShape->panPartStart[i] < 0
|| (psShape->panPartStart[i] >= psShape->nVertices
- && psShape->nVertices > 0) )
+ && psShape->nVertices > 0)
+ || (psShape->panPartStart[i] > 0 && psShape->nVertices == 0) )
{
snprintf(szErrorMsg, sizeof(szErrorMsg),
"Corrupted .shp file : shape %d : panPartStart[%d] = %d, nVertices = %d",
- hEntity, i, psShape->panPartStart[i], psShape->nVertices);
+ hEntity, i, psShape->panPartStart[i], psShape->nVertices);
+ szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
psSHP->sHooks.Error( szErrorMsg );
SHPDestroyObject(psShape);
return NULL;
{
snprintf(szErrorMsg, sizeof(szErrorMsg),
"Corrupted .shp file : shape %d : panPartStart[%d] = %d, panPartStart[%d] = %d",
- hEntity, i, psShape->panPartStart[i], i - 1, psShape->panPartStart[i - 1]);
+ hEntity, i, psShape->panPartStart[i], i - 1, psShape->panPartStart[i - 1]);
+ szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
psSHP->sHooks.Error( szErrorMsg );
SHPDestroyObject(psShape);
return NULL;
if( psShape->nSHPType == SHPT_MULTIPATCH )
{
memcpy( psShape->panPartType, psSHP->pabyRec + nOffset, 4*nParts );
- for( i = 0; i < nParts; i++ )
+ for( i = 0; (int32)i < nParts; i++ )
{
if( bBigEndian ) SwapWord( 4, psShape->panPartType+i );
}
nOffset += 4*nParts;
}
-
+
/* -------------------------------------------------------------------- */
/* Copy out the vertices from the record. */
/* -------------------------------------------------------------------- */
- for( i = 0; i < nPoints; i++ )
+ for( i = 0; (int32)i < nPoints; i++ )
{
memcpy(psShape->padfX + i,
psSHP->pabyRec + nOffset + i * 16,
}
nOffset += 16*nPoints;
-
+
/* -------------------------------------------------------------------- */
/* If we have a Z coordinate, collect that now. */
/* -------------------------------------------------------------------- */
{
memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 );
memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 );
-
+
if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );
if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );
-
- for( i = 0; i < nPoints; i++ )
+
+ for( i = 0; (int32)i < nPoints; i++ )
{
memcpy( psShape->padfZ + i,
psSHP->pabyRec + nOffset + 16 + i*8, 8 );
nOffset += 16 + 8*nPoints;
}
+ else if( psShape->bFastModeReadObject )
+ {
+ psShape->padfZ = NULL;
+ }
/* -------------------------------------------------------------------- */
/* If we have a M measure value, then read it now. We assume */
/* big enough, but really it will only occur for the Z shapes */
/* (options), and the M shapes. */
/* -------------------------------------------------------------------- */
- if( nEntitySize >= nOffset + 16 + 8*nPoints )
+ if( nEntitySize >= (int)(nOffset + 16 + 8*nPoints) )
{
memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );
memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );
-
+
if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );
if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );
-
- for( i = 0; i < nPoints; i++ )
+
+ for( i = 0; (int32)i < nPoints; i++ )
{
memcpy( psShape->padfM + i,
psSHP->pabyRec + nOffset + 16 + i*8, 8 );
}
psShape->bMeasureIsUsed = TRUE;
}
+ else if( psShape->bFastModeReadObject )
+ {
+ psShape->padfM = NULL;
+ }
}
/* ==================================================================== */
|| psShape->nSHPType == SHPT_MULTIPOINTM
|| psShape->nSHPType == SHPT_MULTIPOINTZ )
{
- int32_t nPoints;
+ int32 nPoints;
int i, nOffset;
+ unsigned char* pBuffer = NULL;
+ unsigned char** ppBuffer = NULL;
if ( 44 + 4 > nEntitySize )
{
snprintf(szErrorMsg, sizeof(szErrorMsg),
"Corrupted .shp file : shape %d : nEntitySize = %d",
- hEntity, nEntitySize);
+ hEntity, nEntitySize);
+ szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
psSHP->sHooks.Error( szErrorMsg );
SHPDestroyObject(psShape);
return NULL;
if( bBigEndian ) SwapWord( 4, &nPoints );
- if (nPoints < 0 || nPoints > 50 * 1000 * 1000)
+ /* nPoints is unsigned */
+ if (/* nPoints < 0 || */ nPoints > 50 * 1000 * 1000)
{
snprintf(szErrorMsg, sizeof(szErrorMsg),
- "Corrupted .shp file : shape %d : nPoints = %d",
- hEntity, nPoints);
+ "Corrupted .shp file : shape %d : nPoints = %u",
+ hEntity, nPoints);
+ szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
psSHP->sHooks.Error( szErrorMsg );
SHPDestroyObject(psShape);
return NULL;
if (nRequiredSize > nEntitySize)
{
snprintf(szErrorMsg, sizeof(szErrorMsg),
- "Corrupted .shp file : shape %d : nPoints = %d, nEntitySize = %d",
- hEntity, nPoints, nEntitySize);
+ "Corrupted .shp file : shape %d : nPoints = %u, nEntitySize = %d",
+ hEntity, nPoints, nEntitySize);
+ szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
psSHP->sHooks.Error( szErrorMsg );
SHPDestroyObject(psShape);
return NULL;
}
-
+
+ if( psShape->bFastModeReadObject )
+ {
+ int nObjectBufSize = 4 * sizeof(double) * nPoints;
+ pBuffer = SHPReallocObjectBufIfNecessary(psSHP, nObjectBufSize);
+ ppBuffer = &pBuffer;
+ }
+
psShape->nVertices = nPoints;
- psShape->padfX = (double *) calloc(nPoints,sizeof(double));
- psShape->padfY = (double *) calloc(nPoints,sizeof(double));
- psShape->padfZ = (double *) calloc(nPoints,sizeof(double));
- psShape->padfM = (double *) calloc(nPoints,sizeof(double));
+
+ psShape->padfX = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
+ psShape->padfY = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
+ psShape->padfZ = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
+ psShape->padfM = (double *) SHPAllocBuffer(ppBuffer, sizeof(double) * nPoints);
if (psShape->padfX == NULL ||
psShape->padfY == NULL ||
psShape->padfM == NULL)
{
snprintf(szErrorMsg, sizeof(szErrorMsg),
- "Not enough memory to allocate requested memory (nPoints=%d) for shape %d. "
- "Probably broken SHP file", hEntity, nPoints );
+ "Not enough memory to allocate requested memory (nPoints=%u) for shape %d. "
+ "Probably broken SHP file", nPoints, hEntity );
+ szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
psSHP->sHooks.Error( szErrorMsg );
SHPDestroyObject(psShape);
return NULL;
}
- for( i = 0; i < nPoints; i++ )
+ for( i = 0; (int32)i < nPoints; i++ )
{
memcpy(psShape->padfX+i, psSHP->pabyRec + 48 + 16 * i, 8 );
memcpy(psShape->padfY+i, psSHP->pabyRec + 48 + 16 * i + 8, 8 );
}
nOffset = 48 + 16*nPoints;
-
+
/* -------------------------------------------------------------------- */
/* Get the X/Y bounds. */
/* -------------------------------------------------------------------- */
{
memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 );
memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 );
-
+
if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );
if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );
-
- for( i = 0; i < nPoints; i++ )
+
+ for( i = 0; (int32)i < nPoints; i++ )
{
memcpy( psShape->padfZ + i,
psSHP->pabyRec + nOffset + 16 + i*8, 8 );
nOffset += 16 + 8*nPoints;
}
+ else if( psShape->bFastModeReadObject )
+ psShape->padfZ = NULL;
/* -------------------------------------------------------------------- */
/* If we have a M measure value, then read it now. We assume */
/* big enough, but really it will only occur for the Z shapes */
/* (options), and the M shapes. */
/* -------------------------------------------------------------------- */
- if( nEntitySize >= nOffset + 16 + 8*nPoints )
+ if( nEntitySize >= (int)(nOffset + 16 + 8*nPoints) )
{
memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );
memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );
-
+
if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );
if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );
-
- for( i = 0; i < nPoints; i++ )
+
+ for( i = 0; (int32)i < nPoints; i++ )
{
memcpy( psShape->padfM + i,
psSHP->pabyRec + nOffset + 16 + i*8, 8 );
}
psShape->bMeasureIsUsed = TRUE;
}
+ else if( psShape->bFastModeReadObject )
+ psShape->padfM = NULL;
}
/* ==================================================================== */
|| psShape->nSHPType == SHPT_POINTZ )
{
int nOffset;
-
+
psShape->nVertices = 1;
- psShape->padfX = (double *) calloc(1,sizeof(double));
- psShape->padfY = (double *) calloc(1,sizeof(double));
- psShape->padfZ = (double *) calloc(1,sizeof(double));
- psShape->padfM = (double *) calloc(1,sizeof(double));
+ if( psShape->bFastModeReadObject )
+ {
+ psShape->padfX = &(psShape->dfXMin);
+ psShape->padfY = &(psShape->dfYMin);
+ psShape->padfZ = &(psShape->dfZMin);
+ psShape->padfM = &(psShape->dfMMin);
+ psShape->padfZ[0] = 0.0;
+ psShape->padfM[0] = 0.0;
+ }
+ else
+ {
+ psShape->padfX = (double *) calloc(1,sizeof(double));
+ psShape->padfY = (double *) calloc(1,sizeof(double));
+ psShape->padfZ = (double *) calloc(1,sizeof(double));
+ psShape->padfM = (double *) calloc(1,sizeof(double));
+ }
if (20 + 8 + (( psShape->nSHPType == SHPT_POINTZ ) ? 8 : 0)> nEntitySize)
{
snprintf(szErrorMsg, sizeof(szErrorMsg),
"Corrupted .shp file : shape %d : nEntitySize = %d",
- hEntity, nEntitySize);
+ hEntity, nEntitySize);
+ szErrorMsg[sizeof(szErrorMsg)-1] = '\0';
psSHP->sHooks.Error( szErrorMsg );
SHPDestroyObject(psShape);
return NULL;
if( bBigEndian ) SwapWord( 8, psShape->padfY );
nOffset = 20 + 8;
-
+
/* -------------------------------------------------------------------- */
/* If we have a Z coordinate, collect that now. */
/* -------------------------------------------------------------------- */
if( psShape->nSHPType == SHPT_POINTZ )
{
memcpy( psShape->padfZ, psSHP->pabyRec + nOffset, 8 );
-
+
if( bBigEndian ) SwapWord( 8, psShape->padfZ );
-
+
nOffset += 8;
}
if( nEntitySize >= nOffset + 8 )
{
memcpy( psShape->padfM, psSHP->pabyRec + nOffset, 8 );
-
+
if( bBigEndian ) SwapWord( 8, psShape->padfM );
psShape->bMeasureIsUsed = TRUE;
}
case SHPT_MULTIPOINT:
return "MultiPoint";
-
+
case SHPT_POINTZ:
return "PointZ";
case SHPT_MULTIPOINTZ:
return "MultiPointZ";
-
+
case SHPT_POINTM:
return "PointM";
{
case SHPP_TRISTRIP:
return "TriangleStrip";
-
+
case SHPP_TRIFAN:
return "TriangleFan";
{
if( psShape == NULL )
return;
-
+
+ if( psShape->bFastModeReadObject )
+ {
+ psShape->bFastModeReadObject = FALSE;
+ return;
+ }
+
if( psShape->padfX != NULL )
free( psShape->padfX );
if( psShape->padfY != NULL )
/************************************************************************/
int SHPAPI_CALL
-SHPRewindObject( SHPHandle hSHP, SHPObject * psObject )
-
+SHPRewindObject( CPL_UNUSED SHPHandle hSHP,
+ SHPObject * psObject )
{
int iOpRing, bAltered = 0;
if( iCheckRing == iOpRing )
continue;
-
+
nVertStart = psObject->panPartStart[iCheckRing];
if( iCheckRing == psObject->nParts-1 )
- nVertCount = psObject->nVertices
+ nVertCount = psObject->nVertices
- psObject->panPartStart[iCheckRing];
else
- nVertCount = psObject->panPartStart[iCheckRing+1]
+ nVertCount = psObject->panPartStart[iCheckRing+1]
- psObject->panPartStart[iCheckRing];
for( iEdge = 0; iEdge < nVertCount; iEdge++ )
/* Rule #1:
* Test whether the edge 'straddles' the horizontal ray from the test point (dfTestY,dfTestY)
- * The rule #1 also excludes edges collinear with the ray.
+ * The rule #1 also excludes edges colinear with the ray.
*/
if ( ( psObject->padfY[iEdge+nVertStart] < dfTestY
&& dfTestY <= psObject->padfY[iNext+nVertStart] )
/* Rule #2:
* Test if edge-ray intersection is on the right from the test point (dfTestY,dfTestY)
*/
- double const intersect =
+ double const intersect =
( psObject->padfX[iEdge+nVertStart]
- + ( dfTestY - psObject->padfY[iEdge+nVertStart] )
+ + ( dfTestY - psObject->padfY[iEdge+nVertStart] )
/ ( psObject->padfY[iNext+nVertStart] - psObject->padfY[iEdge+nVertStart] )
* ( psObject->padfX[iNext+nVertStart] - psObject->padfX[iEdge+nVertStart] ) );
{
bInner = !bInner;
}
- }
+ }
}
} /* for iCheckRing */
if( iOpRing == psObject->nParts-1 )
nVertCount = psObject->nVertices - psObject->panPartStart[iOpRing];
else
- nVertCount = psObject->panPartStart[iOpRing+1]
+ nVertCount = psObject->panPartStart[iOpRing+1]
- psObject->panPartStart[iOpRing];
if (nVertCount < 2)
/* Swap X */
dfSaved = psObject->padfX[nVertStart+i];
- psObject->padfX[nVertStart+i] =
+ psObject->padfX[nVertStart+i] =
psObject->padfX[nVertStart+nVertCount-i-1];
psObject->padfX[nVertStart+nVertCount-i-1] = dfSaved;
/* Swap Y */
dfSaved = psObject->padfY[nVertStart+i];
- psObject->padfY[nVertStart+i] =
+ psObject->padfY[nVertStart+i] =
psObject->padfY[nVertStart+nVertCount-i-1];
psObject->padfY[nVertStart+nVertCount-i-1] = dfSaved;
if( psObject->padfZ )
{
dfSaved = psObject->padfZ[nVertStart+i];
- psObject->padfZ[nVertStart+i] =
+ psObject->padfZ[nVertStart+i] =
psObject->padfZ[nVertStart+nVertCount-i-1];
psObject->padfZ[nVertStart+nVertCount-i-1] = dfSaved;
}
if( psObject->padfM )
{
dfSaved = psObject->padfM[nVertStart+i];
- psObject->padfM[nVertStart+i] =
+ psObject->padfM[nVertStart+i] =
psObject->padfM[nVertStart+nVertCount-i-1];
psObject->padfM[nVertStart+nVertCount-i-1] = dfSaved;
}